Skip to content

hyera.cli

Command-line interface for hyera, built on duho.

Accepts puppet lookup's own flag set (see README.md "Command line"):

hyera KEY --hiera_config hiera.yaml --facts facts.yaml --node N

Designed for unattended use: no interactive prompts, deterministic output, and exit codes: 0 found (or --default printed), 1 key not found, 2 any other error (one stderr line; -v or DUHO_TRACEBACK=1 adds the traceback), 130 interrupted. Output is rendered the way puppet lookup --render-as s|json|yaml does (hyera._output.render), written as UTF-8 bytes with LF line endings whatever the console/locale encoding.

Lookup

Bases: LoggingArgs, Cli

Look up keys in Hiera data the way puppet lookup does.

Needs --facts. Exit status: 0 found (or --default printed), 1 no key found, 2 any other error, 130 interrupted.

basemodulepath = None class-attribute instance-attribute

Module directories shared by every environment, separated by the OS path separator; omitted, none.

codedir = None class-attribute instance-attribute

Puppet's $codedir; omitted, Puppet's own default for the platform.

debug = False class-attribute instance-attribute

Log debug messages, same as -vv.

default = None class-attribute instance-attribute

Text printed when no key is found; omitted, a miss exits 1 and prints nothing.

environment = None class-attribute instance-attribute

Environment name; omitted, production.

environmentpath = None class-attribute instance-attribute

Environment directories separated by the OS path separator; omitted, no environment layer.

explain = False class-attribute instance-attribute

Print how the value was found instead of the value; omitted, print the value.

explain_options = False class-attribute instance-attribute

Print only how lookup_options was assembled; omitted, print the value.

facts = None class-attribute instance-attribute

REQUIRED: facts file, .json, .yaml or .yml (another name is read as JSON, then YAML); without it every lookup fails.

hiera_config = None class-attribute instance-attribute

Path to the base hiera.yaml; omitted, ./hiera.yaml if it exists, else Puppet's built-in configuration.

keys = None class-attribute instance-attribute

Keys to look up, the first one found wins; omit only with --explain-options.

knock_out_prefix = None class-attribute instance-attribute

With --merge deep: a regular expression; matching array elements are removed and matching strings blanked; omitted, nothing is removed.

merge = None class-attribute instance-attribute

Merge strategy first, unique, hash or deep; omitted, the key's lookup_options decide, else first.

merge_hash_arrays = False class-attribute instance-attribute

With --merge deep: merge hashes inside arrays by position; omitted, array elements are united.

modulepath = None class-attribute instance-attribute

Module directories of the environment, separated by the OS path separator; omitted, the environment's own.

node = None class-attribute instance-attribute

Node name used in messages only; omitted, the local host name.

render_as = None class-attribute instance-attribute

Output format s, json or yaml; omitted, yaml (s when explaining).

scope = None class-attribute instance-attribute

Repeatable NAME=VALUE node parameter, VALUE is YAML and a dotted NAME builds a hash; omitted, none.

sort_merged_arrays = False class-attribute instance-attribute

With --merge deep: sort merged arrays; omitted, they keep their order.

strict = None class-attribute instance-attribute

Undefined-variable handling: off, warning or error; omitted, warning.

value_type = None class-attribute instance-attribute

Puppet type the value (and --default) must have, e.g. Array[String]; omitted, any value.

__call__()

Run the lookup duho parsed into this instance's fields and return the process exit code (see the class docstring).

Returns:

Type Description
int

the process exit code.

Source code in src/hyera/cli/__init__.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
def __call__(self) -> int:
    """Run the lookup duho parsed into this instance's fields and
    return the process exit code (see the class docstring).

    :returns: the process exit code.
    """
    opts = _free_text(self)
    keys = list(self.keys or ()) + list(self._passthrough_ or ())
    try:
        merge_options = _merge_options(
            opts["merge"],
            opts["knock_out_prefix"],
            self.sort_merged_arrays,
            self.merge_hash_arrays,
        )
    except _UsageError as e:
        return self._fail(str(e))

    boundary = _mcp_boundary.active()
    try:
        if boundary is not None:
            boundary.check(opts)
    except _UsageError as e:
        return self._fail(str(e))

    explaining = self.explain or self.explain_options
    only_options = self.explain_options and not self.explain
    if not keys:
        if not only_options:
            return self._fail("No keys were given to lookup.")
        keys = ["__global__"]

    render_as = opts["render_as"]
    fmt = (render_as if render_as is not None else "yaml").lower()
    if render_as is None and explaining:
        fmt = "s"
    if Backend.find(fmt, kind="render") is None:
        return self._fail("Unknown rendering format '{}'".format(fmt))

    joined_keys = ", ".join(keys)
    try:
        scope = _build_scope(
            _parse_scope(opts["scope"]),
            opts["facts"],
            opts["node"],
            opts["environment"],
            opts["strict"],
        )
    except (_UsageError, BackendError, TypeError, ValueError) as e:
        return self._fail(str(e))

    try:
        outcome = _resolve(
            opts, scope, keys, merge_options, explaining, only_options, boundary
        )
    except KeyNotFoundError as e:
        # Puppet's own miss prints nothing and exits 1, with or
        # without -v; only -d/--debug (or -vv, or --loglevel) shows
        # this DEBUG line.
        _LOGGER.debug("%s", e)
        return 1
    except Exception as e:  # HieraError, OSError, anything unexpected
        return self._fail(
            "Lookup of key '{}' failed: {}".format(joined_keys, _describe(e))
        )

    try:
        text = _render(fmt, outcome, explaining)
    except Exception as e:
        return self._fail(
            "Cannot render the value of key '{}': {}".format(
                joined_keys, _describe(e)
            )
        )
    try:
        _emit(text)
    except OSError:
        # The reader is gone or the device is full: nothing can be
        # reported on stdout, and one more line on stderr would be
        # noise for a caller that stopped listening.
        _silence_stdout()
        return 2
    return 0

main(argv=None)

The hyera console script and python -m hyera entry point.

Parameters:

Name Type Description Default
argv Optional[Sequence[str]]

the argument vector, excluding the program name; defaults to sys.argv[1:].

None

Returns:

Type Description
int

0 found (or --default printed), 1 no key found, 2 any other error, or the CLI extra is not installed, 130 interrupted.

Source code in src/hyera/cli/__init__.py
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
def main(argv: _ty.Optional[_ty.Sequence[str]] = None) -> int:
    """The ``hyera`` console script and ``python -m hyera`` entry point.

    :param argv: the argument vector, excluding the program name; defaults
        to ``sys.argv[1:]``.
    :returns: 0 found (or ``--default`` printed), 1 no key found, 2 any
        other error, or the CLI extra is not installed, 130 interrupted.
    """
    # duho.main sets up stderr logging (honoring -v/-q/--loglevel) and
    # dispatches to Lookup.__call__, whose int return becomes the exit code.
    if duho is None:
        print(_NO_CLI_EXTRA_HINT, file=_sys.stderr)
        return 2
    try:
        _mcp_boundary.activate()
    except _UsageError as e:
        print("hyera: {}".format(e), file=_sys.stderr)
        return 2
    argv = list(_sys.argv[1:] if argv is None else argv)
    try:
        return duho.main(Lookup, argv)
    except KeyboardInterrupt:
        return 130