Carthage Modeling Module
Base Models
- class carthage.modeling.CarthageLayout(**kwargs)
CarthageLayout is typically the top level class in a set of Carthage models. It is a
ModelGroupthat represents a complete collection of objects modeled by Carthage. The primary purpose of this class is to signify the top of a collection of objects; the layout is generally the place to start when examining a collection of models.However, a layout differs from a ModelGroup in two ways:
carthage-runner looks for a
CarthageLayoutto instantiate after loading plugins. If the console is used, the layout is made available in the layout local variable of the console. If a command is run, the command is run in the context of the layout.Layouts that set the
carthage.kvstore.persistent_seed_pathin the context of theirInjectorwill have persistent assignments of things like IP addresses and MAC addresses loaded from the seed path when instantiated.
- 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.
- layout_uuid()
Returns a uuid for this layout; based on layout_name or the class’s qualname.
- class carthage.modeling.InjectableModel(*args, _not_transcluded=None, **kwargs)
- class carthage.modeling.MachineModel(**kwargs)
Represents the aspects of a
Machinethat are independent of the implementation of that machine. Typically includes things like:Network configuration (
NetworkConfigConfiguration for devops tools like Ansible
Selecting the target implementation (whether the machine will be a VM, container, or hosted on real hardware)
Applications that want to reason about the abstract environment typically only need to instantiate models. Applications that want to build VMs or effect changes to real hardware instantiate the machine implementations. This class is the modeling extensions to
carthage.machine.AbstractMachineModel.If a MachineModel contains reference to
setup_tasks, then it will automatically gainSetupTaskMixinas a base class. Similarly, ifmodel_mixin_for()is used to decorate a class in the sameCarthageLayoutencountered before the MachineModel, then that class will be added as an implicit base class of the model.Class Parameters passed in as keywords on the class statement:
- param template:
True if this class represents a base class or mixin rather than a actual model of a specific machine.
- param mixin_key:
The
InjectionKeyto use to search for mixins.
Any
carthage.network.NetworkConfigpresent in the MachineModel will be used as the network configuration.Every
carthage.machine.BaseCustomization(including MachineCustomization, FilesystemCustomization and ContainerCustomization) will be integrated into the resulting machine:If the customization is called cust, then a method will be added to the machine cust_task which is a
carthage.machine.customization_task()to run the customization.On the model, cust will become a method that will produce an instance of the customization applied to the machine.
For example:
class server(MachineModel): class install_software(MachineCustomization): webserver_role = ansible_role_task('webserver') database_role = ansible_role_task('database')
Then server.machine will have a method install_software_task which will run both ansible roles assuming they have not already been run. model.install_software will produce an instance of the customization applied to model.machine. model.install_software.database_role() is a method that will force the database_role to run even if it appears up to date.
- ansible_groups: Sequence[str]
A set of ansible groups to add a model to; see
carthage.modeling.ansible.enable_modeling_ansible().
- machine_mixins = ()
Sequence of classes to be mixed into the resulting machine implementation
- classmethod our_key()
Returns the globally unique InjectionKey by which this model is known.
- async resolve_networking(*args, **kwargs)
See
resolve_networking()for documentation.In adition to the standard behavior, if
machine_type()is an instance ofLocalMachineMixin,then call
carthage.local.process_local_network_config()to learn about local bridges.
- stamp_subdir()
The part of
stamp_path()after config.stamp_dir. For example for a podman container calledexample.comthis might bepodman/containers/example.com
- classmethod supplementary_injection_keys(k)
Exclude
AbstractMachineModelandMachineModelwithout constraints from the set of keys that are registered. These keys are searched to find the current MachineModel, and if they are implicitly set it can produce cases where a MachineModel is accidentally available. Also, it makes it difficult to have one MachineModel contained within another.
- class carthage.modeling.ModelContainer(*args, _not_transcluded=None, **kwargs)
Decorators
- carthage.modeling.decorators.dynamic_name(name)
A decorator to be used in a modeling type to supply a dynamic name. Example:
for i in range(3): @dynamic_name(f'i{i+1}')
class ignored: square = i*i
Will define threevariables i1 through i3, with values of squares (i1 = 0, i2 =1, i3 = 4).
- carthage.modeling.decorators.globally_unique_key(key: InjectionKey | Callable[[object], InjectionKey])
Decorate a value to indicate that key is a globally unique
InjectionKeythat should provide the given value. Globally unique keys are not extended with additional constraints when propagated up throughModelingContainers.- Parameters:
key – A callback that maps the value to a key. Alternatively, simply the
InjectionKeyto use.
- class carthage.modeling.decorators.injector_access(key, target=None)
Usage:
val = injector_access("foo")
At runtime,
model_instance.valwill be memoized tomodel_instance.injector.get_instance("foo").- key: InjectionKey
The injection key to be accessed.
- carthage.modeling.decorators.machine_mixin(name=None)
Mark a class (subclass of
Machinetypically) as something that should be mixed in to any machine declared lower in the injector hierarchy withing modeling classes. To accomplish the same thing outside of modeling classes:injector.add_provider(InjectionKey(MachineMixin, name = "some_name"), dependency_quote(mixin_class))
The call to :func:~carthage.dependency_injection.dependency_quote` is required to prevent the injector from trying to build a machine when the Mixin is looked up.
- carthage.modeling.decorators.model_mixin_for(**constraints)
Indicate that a given model supplements a model declared automatically. The simplest usage looks like:
@model_mixin_for(host = "foo.com") class foomixin(MachineModel): # stuff added to foo.com class foo(MachineModel): name = "foo.com" # Also inherits from foomixin
In the above example it would be simpler to list foomixin as a base for foo. However when a loop instantiates a number of models with a dynamic name, model_mixin_for provides value:
for c in ('foo', 'bar', 'baz'): @dynamic_name(c) class model(MachineModel): name = c+".com"
In the above usage, the loop would need to get more complicated to only add foomixin to the dynamically generated class for the
foo.commodel. In this case model_mixin_for provides value.IN a more complex usage, model_mixin_for can be used in a layout that will transclude a model using
carthage.modeling.base.model_bases(). This is similar totransclude_overrides()except that rather than entirely replacing the model, model_mixin_for simply adds a base.
- carthage.modeling.decorators.propagate_key(key, obj=None)
Indicate a set of keys that should be propagated up in a container:
class foo(ModelingContainer): @propagate_key(InjectionKey(Baz, target = 42)) class ourbaz(Baz): ...
When foo is included in a container, then the Baz injection key will be propagated up to dependencies provided by that container. Since the key was not marked globally unique, constraints from foo.our_key() will be added to it as it is propagated.
keys are also provided by the contained class as if
provides()orglobally_unique()were called.Propagating a key up is typically an interface point; rather than propagating all keys related to an object up, propagate the keys that will be understood by the environment. Examples of usage include:
Any
AbstractMachineModelwith a host constraint is collected to find all the machine models in a layout
- carthage.modeling.decorators.provides(*keys)
Indicate that the decorated value provides these InjectionKeys
- carthage.modeling.decorators.transclude_overrides(key: InjectionKey = None)
Decorator indicating that the decorated item should be overridden by one from the injector against which the containing layout is eventually instantiated. When a
InjectableModelis eventually instantiated, before an overridable key is added to the local injector, it is searched for in the instantiating injector. If it is found, the key is not registered. This has the effect of using the dependency provider in the instantiating injector rather than the one included in the layout.- Parameters:
key – If supplied, is the key expected to be registered with the transcluding injector to override this object. If not supplied, the object must have a globally unique key.
Example usage:
class layout(CarthageLayout): @transclude_overrides(key=InjectionKey("network")) class network(NetworkModel): # ...
If
layoutis instantiated in a injector that provides a dependency forInjectionKey('network'), then that object will be used rather than thenetworkclass within the layout. Since thenetworkproperty is aninjector_acess(),layout_instance.networkwill refer to the object in the instantiating injector rather than an instance oflayout.network.