progfigsite
inventory module¶
Required attributes and function calls
sitewrapper.set_progfigsite_by_module_name(site_name)
You must call this function to tell progfiguration core the name of the package. This must happen before any progfiguration core functions are called. See also
progfiguration.sitewrapper.set_progfigsite_by_module_name()
.hoststore
An implementation of the
progfiguration.inventory.invstores.HostStore
protocol. Progfiguration core ships withprogfiguration.sitehelpers.memhosts.MemoryHostStore
which can be instantiated directly, or viaprogfiguration.sitehelpers.invconf.hosts_conf()
and a configuration file. Sites are free to implement their own alternative.secretstore
An implementation of the
progfiguration.inventory.invstores.SecretStore
protocol. Progfiguration core ships withprogfiguration.sitehelpers.agesecrets.AgeSecretStore
, which can be instantiated directly, or viaprogfiguration.sitehelpers.invconf.secrets_conf()
and a configuration file. Sites are free to implement their own alternative.mint_version()
A function that takes no arguments and returns a valid pip version number.
This function should return a new version number, suitable for the next build of the pacakge. (This is different from the
get_version()
function in progfigsite root members, which returns the current version number.)Progfiguration core ships with
progfiguration.sitehelpers.siteversion.mint_version_factory_from_epoch()
, which will return a function that uses the epoch time in the version number. Some implementations might prefer to implement their ownmint_version()
, perhaps to pull the version number from an environment variable injected by a CI service, etc.
progfigsite
inventory.conf
File¶
An inventory.conf
file is not technically part of progfiguration core,
but it can be used with
progfiguration.sitehelpers.invconf.hosts_conf()
and
progfiguration.sitehelpers.invconf.secrets_conf()
to create a
host store and
secrets store respectively.
Here’s an example from example_site
:
[secrets]
# The controller has an age key which can be used to decrypt any secret.
# When this file is not present, progfiguration will still work,
# but activities that require the secret key will throw errors.
controller_age_path = /path/to/controller.age
# We must hard code the public key in this file as well,
# so that it is available even when we aren't running on the controller.
controller_age_pub = paste the public key here
# The default/fallback location for the age key on each node.
node_fallback_age_path = /path/to/node.age
####
# Assign group membership
# You can specify more than one group by separating items with newlines or spaces
[groups]
group1 = node1
# group2 = node1 node2 node3
####
# Assign each node to a function.
# WARNING: Any node not listed here will not be visible to progfiguration,
# meaning that it cannot be deployed to, will not be in the 'universal' group, etc.
[node_function_map]
node1 = func1
####
# Set the list of roles for each function
# Roles can be separated by newlines or spaces
[function_role_map]
func1 = settz
# func2 = settz otherrole asdf etc
# TODO: fall back to this role so that we don't have to place new nodes in role_function_map
# and they will still come up.
default = settz
By itself, that inventory file does nothing,
but when referenced in the site’s inventory module
it generates the host and secret stores.
Here is the inventory module from example_site
:
"""Inventory module.
Must call :meth:`progfiguration.sitewrapper.set_progfigsite_by_module_name` in this module.
May use helper functions like
:meth:`progfiguration.sitehelpers.invconf.hosts_conf` and
:meth:`progfiguration.sitehelpers.invconf.secrets_conf`
to create the hoststore and secretstore.
"""
from progfiguration import sitewrapper
from progfiguration.sitehelpers import siteversion
from progfiguration.sitehelpers.invconf import hosts_conf, secrets_conf
# The progfigsite package must be set before calling anything else from progfiguration core.
sitewrapper.set_progfigsite_by_module_name("example_site")
hoststore = hosts_conf("inventory.conf")
"""The hoststore for the site
The :meth:`progfiguration.sitehelpers.invconf.hosts_conf` function
returns a :class:`progfiguration.sitehelpers.invconf.MemoryHostStore`.
The path we pass to it can be included in the site package
and found relative to the site package root.
"""
secretstore = secrets_conf("inventory.conf")
"""The secretstore for the site
The :meth:`progfiguration.sitehelpers.invconf.secrets_conf` function
returns a :class:`progfiguration.sitehelpers.invconf.AgeSecretStore`.
Note that we pass it the same config file -- it reads different sections.
"""
mint_version = siteversion.mint_version_factory_from_epoch(major=1, minor=0)
"""A function that generates a new version when it's called.
Set it from :meth:`sitehelpers.siteversion.mint_version_factory_from_epoch`,
which returns a ``mint_version()`` implementation
that returns f"{maj}.{min}.{epoch}".
Sites can write their own ``mint_version()`` if they wish,
perhaps pulling the version from a build number in a CI system.
"""
Inventory without inventory.conf
¶
As noted, you can instantiate the HostStore
and SecretStore
classes yourself,
as in this example.
"""Inventory module.
Must call :meth:`progfiguration.sitewrapper.set_progfigsite_by_module_name` in this module.
May use helper functions like
:meth:`progfiguration.sitehelpers.invconf.hosts_conf` and
:meth:`progfiguration.sitehelpers.invconf.secrets_conf`
to create the hoststore and secretstore.
"""
from pathlib import Path
from progfiguration import sitewrapper
from progfiguration.sitehelpers.agesecrets import AgeSecretStore
from progfiguration.sitehelpers.memhosts import MemoryHostStore
# The progfigsite package must be set before calling anything else from progfiguration core.
sitewrapper.set_progfigsite_by_module_name("nnss_progfigsite")
# Use progfiguration core to create an inventory
hoststore = MemoryHostStore(
groups={"group1": ["node1"]},
node_function_map={"node1": "func1"},
function_role_map={
"func1": ["settz"],
"default": ["settz"],
},
)
"""The site's inventory"""
secretstore = AgeSecretStore(
# This pubkey matches the private key we keep in the package directory.
controller_age_pubkey="age1dmxq0tws40d8npseun9azpq65smpyd2kqfyj0ytlk6m7trn7nsxqnsrag2",
decryption_age_privkey_path_list=[
# Let the unit tests find controller.age in this file's parent directory.
# Normally you would not want to keep it here,
# as it would mean your controller key is in version control.
(Path(__file__).parent.parent / "controller.age").as_posix(),
# An example default value, not used in our unit tests
"/default/path/for/nodes/key.age",
],
)
"""The method for storing secrets."""
def mint_version() -> str:
"""Mint a new version number
This function is called by progfiguration core to generate a version number.
It may be called by site-specific code as well.
It should return a string that is a valid pip version number.
(If you are also building other packages like RPMs,
make sure to use a version number that is valid for all of them.)
"""
from datetime import datetime
dt = datetime.utcnow()
epoch = int(dt.timestamp())
version = f"1.0.{epoch}"
return version