mod_env can be None. Make it an empty dict in that case to take a
little burden off the implementations in the derived classes.
Signed-off-by: Jan Lindemann <jan@janware.com>
Since commit 02697af5, ExecContext.run() returns bytes for stdout and
stderr and fixes that in calling code. The thing it did not fix was
the code calling run_cmd(), which also made return bytes. This commit
catches up on that.
Signed-off-by: Jan Lindemann <jan@janware.com>
Distro's sudo() and run() wrappers are not flagged async. It still
works, because throughout jw-pkg all callers expect a coroutine
return value, but flagging them as async makes the return value
obvious.
Signed-off-by: Jan Lindemann <jan@janware.com>
Move the code of SSHClientInternal and SSCClientCmd into lib.ec.ssh,
as "Paramiko" and "Exec", respectively. This makes the class layout
a little more modular, and along the way fixes a bug where
SSHClientInternal could be instantiated but was unusable (if the
Paramiko is not installed).
Signed-off-by: Jan Lindemann <jan@janware.com>
ExecContext's .sudo() omits many of run()'s parameters, and this
commit adds them. To avoid redundancy around repeating and massaging
the long parameter list of both functions and their return values, it
also adds some deeper changes:
- Make run(), _run(), sudo() and _sudo() always return instances of
Result. Before it was allowed to return a triplet of stdout,
stderr, and exit status.
- Have ExecContext stay out of the business of decoding the result
entirely. Result provides a convenience method .decode()
operating on stdout and stderr and leaves the decision to the
caller.
This entails miniscule adaptations in calling code, namely in
App.os_release, util.get_profile_env() and CmdListRepos._run().
- Wrap the _run() and _sudo() callbacks in a context manager object
of type CallContext to avoid code duplication.
- Consistently name the first argument to run(), _run(), sudo() and
_sudo() "cmd", not "args". The latter suggests that the caller is
omitting the executable, which is not the case.
Signed-off-by: Jan Lindemann <jan@janware.com>
Don't open and parse /etc/os-release with Python built-in functions.
Spawn "cat /etc/os-release" as a subprocess and capture the output
for parsing instead. The obvious advantage is that this also works
with a remote shell.
Signed-off-by: Jan Lindemann <jan@janware.com>
Use the AsyncRunner class introduced in the previous commit to add a
call_async() method, allowing to run async functions from sync
functions by spawning an extra event loop.
Signed-off-by: Jan Lindemann <jan@janware.com>
Add class AsyncRunner. This is a wrapper around the ceremony needed
to spawn an extra event loop in a synchronous function which wants to
call an async function.
Guido van Rossum considers it bad design that such a function exists
in the first place. While that may be true in the long run also for
jw-pkg, at this point I'm unwilling to flag every lazyly initialized
App property as async. It's not clear, yet, which will be async and
which not, and I dread the churn. So I will accept this as a
minimally invasive helper for now. When the API has stabilized, a
design without it may be better.
Signed-off-by: Jan Lindemann <jan@janware.com>
Expose App's __eloop member containing the application's main event
loop to allow outside async event loop trickery.
Signed-off-by: Jan Lindemann <jan@janware.com>
Take implementation burden from the derived classes _run() callback
by moving the respective code into the run() wrapper methods of the
base class.
Signed-off-by: Jan Lindemann <jan@janware.com>
Remove the key_filename parameter from the call to Paramiko's
connect(). It's user-dependent, and the current DevOps implementation
relies on having a SSH_AUTH_SOCK in the environment, anyway.
Signed-off-by: janware DevOps <devops@janware.com>
Add a wrapper around urlparse() and Paramiko's connect() function, in
order to log some more info in case an exception is thrown.
Signed-off-by: Jan Lindemann <jan@janware.com>
Take a positional uri argument to the constructor of ExecContext,
forcing SSHClient to follow suit. The latter was instantiated with a
hostname as only argument up to now, which still works as a special
case of an uri.
Signed-off-by: Jan Lindemann <jan@janware.com>
Use SSHClient as an ExecContext, i.e. use the .run() method instead
of .run_cmd(). Also, let SSHClient decide which implementation to
use.
Signed-off-by: Jan Lindemann <jan@janware.com>
Code beautification chore: Move the public methods of SSHClients to
the bottom of the class to be consistent with other classes.
Signed-off-by: Jan Lindemann <jan@janware.com>
Align the prototype of SSHClient.run_cmd() to ExecContext.run(). This
is a push towards making the SSHClient code an ExceContext, too. Some
arguments still log a warning or outright raise NotImplementedError.
Signed-off-by: Jan Lindemann <jan@janware.com>
CmdInfo._expand_macros() raises a custom exception during exception
handling. Replace that by logging some details and raising the
original exception to keep the stack trace readable.
Signed-off-by: Jan Lindemann <jan@janware.com>
Make SSHClient accept a list of strings for the cmd argument to align
with the other run_cmd() functions in jw-pkg.
Signed-off-by: Jan Lindemann <jan@janware.com>
Make all backend package manager prototypes have the same arguments:
yum(self, args: list[str], verbose: bool=True, sudo: bool=True)
This also implies having them behave equally verbose, unless
otherwise specified by the caller. This changes the default for
Debian.
Signed-off-by: Jan Lindemann <jan@janware.com>
pkg_relations_list() has an intricate case distinction around
expand_semver_revision_range, clean that up.
Signed-off-by: Jan Lindemann <jan@janware.com>
In a push to eventually merge the classes, somewhat align the
command-line API of CmdRequiredOsPkg to the one of
BaseCmdPkgRelations by using dependency flavours as mandatory, first
argument.
Signed-off-by: Jan Lindemann <jan@janware.com>
To support the pkg-install-testbuild-deps target, a selector is
needed listing all prerequisites to be installed except the project
under test. --hide-self should be useful for that.
Signed-off-by: Jan Lindemann <jan@janware.com>
In a push to eventually merge class CmdRequiredOsPkg into this class,
add the --skip-excluded option required by it.
Signed-off-by: Jan Lindemann <jan@janware.com>
In a push to eventually merge class CmdRequiredOsPkg into this class,
add the --quote option required by it.
Signed-off-by: Jan Lindemann <jan@janware.com>
Add a function pkg_relations_list(), doing pretty much the same as
pkg_relations(), but taking individual arguments instead of an
argparse.Namespace args argument, in order to provide the
functionality to derived classes.
Signed-off-by: Jan Lindemann <jan@janware.com>
In commands taking lists of packages, namely install, delete and
pkg_files, don't bother asking the backend. Uniformly log a warning
and return successfully.
Signed-off-by: Jan Lindemann <jan@janware.com>
Add support for --syntax to BaseCmdPkgRelations.pkg_relations(), and
default to 'semver', i.e. the current state of affairs. If that's
changed to 'debian', relations declared in project.conf as
pkg.requires.os.devel = jw-pkg-devel > 1.2.3
will be output as
jw-pkg-devel >> 1.2.3
which is what Debian expects.
Signed-off-by: Jan Lindemann <jan@janware.com>
Add support for --expand-semver-revision-range to
cmds.projects.BaseCmdPkgRelations.pkg_relations(). The options turns
a dependency in projects.conf
pkg.requires.os.devel = jw-pkg-devel = VERSION
into
jw-pkg-devel >= 1.2.3, jw-pkg-devel < 1.2.4
Note that this will break as soon as a real range is specified in
projects.conf. To be fixed later, this commit is at least less
breakage than before.
Signed-off-by: Jan Lindemann <jan@janware.com>
"getting value xxx for project" is a prominent debug log message but
ugly. Beautify to e.g.:
Lookup jw-fail2ban -> jw-pkg / version
Meaning project "jw-fail2ban" looks up the value for key "version" in
project "jw-pkg".
Signed-off-by: Jan Lindemann <jan@janware.com>
The output of
jw.pkg.py projects required-os-pkg --flavours release
should include all packages required by flavour devel, because during
the release process, -devel and -run packages are both installed, and
installing the -devel package is only possible if its dependencies
are installed.
Signed-off-by: Jan Lindemann <jan@janware.com>
Don't mention "error" in log message for exit codes > 0 from spawned
processes, because sometimes they don't mean an error.
Signed-off-by: Jan Lindemann <jan@janware.com>
Add support for the -o (--owner) -g (--group) -m (--mode) options.
They allow to specify a default for compiling templates, but _don't_
override what's in the #conf: specification line in .jw-tmpl or
.jw-secret files.
Signed-off-by: Jan Lindemann <jan@janware.com>
Support option --all to jw-pkg.py secrets list-compilation-output and
list-secrets (CmdListCompilationOutput & CmdSecrets). This allows
them to also report non-existent files.
Signed-off-by: Jan Lindemann <jan@janware.com>
Fix errors dug up by testing on Kali Linux 2026.1:
- Nested class Cmds.Attrs is constructed without scope
- "replace" falls back to empty list, not empty dictionary
Signed-off-by: Jan Lindemann <jan@janware.com>
jw-pkg.py secrets [sub-command] [packages] is a set of utility
commands designed to manage configuration files containing secrets.
To keep secrets from leaking via version control or packages, a
_template_ should be packaged for every sensitive configuration file.
Then, during post-install, configuration files can be generated from
packaged templates via
jw-pkg.py secrets compile-templates <package> <package> ...
During post-uninstall
jw-pkg.py secrets rm-compilation-output <package> <package> ...
removes them.
Not specifying any packages will compile or remove all templates on
the system.
To identify which files to consider and generate or remove, the
compilation scans <package> for files ending in .jw-tmpl. For each
match, e.g.
/path/to/some.conf.jw-tmpl
it will read key-value pairs from
/path/to/some.conf.jw-secret
and generate
/path/to/some.conf
from it, replacing all keys by their respective values. The file
attributes of the generated file can be determined by the first line:
of some.conf.jw-tmpl or some.conf.jw-secret:
# conf: owner=mysql; group=mysql; mode=0640
There are other commands for managing all secrets on the system at
once, see jw-pkg.py secrets --help:
compile-templates Compile package template files
list-compilation-output
List package compilation output files
list-secrets List package secret files
list-templates List package template files
rm-compilation-output
Remove package compilation output files
Signed-off-by: Jan Lindemann <jan@janware.com>