Skip to content

Commit 5906eeb

Browse files
committed
18146 omd create: Distinguish failures by exit status
SUP-24001 Change-Id: Ibe3b21e80881c8f922dee9337279116067118b82
1 parent fdb4d06 commit 5906eeb

2 files changed

Lines changed: 55 additions & 5 deletions

File tree

.werks/18146.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[//]: # (werk v2)
2+
# omd create: Detect if crontab cannot be accessed
3+
4+
key | value
5+
---------- | ---
6+
date | 2025-06-26T09:30:35+00:00
7+
version | 2.5.0b1
8+
class | feature
9+
edition | cre
10+
component | omd
11+
level | 1
12+
compatible | yes
13+
14+
With this Werk, `omd create` will emit different exit codes based on errors it encountered:
15+
16+
0 -> Site creation was successful.
17+
1 -> An exception occured and the site creation was aborted.
18+
2 -> An issue was detected that requires manual intervention to resolve.
19+
20+
Currently, the exit code 2 case is only triggered when a site user is unable to access `crontab`, which is required for a site to work properly.
21+

omd/packages/omd/omdlib/main.py

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from __future__ import annotations
99

1010
import contextlib
11+
import enum
1112
import errno
1213
import fcntl
1314
import io
@@ -2030,6 +2031,19 @@ def use_update_alternatives() -> bool:
20302031
return os.path.exists("/var/lib/dpkg/alternatives/omd")
20312032

20322033

2034+
def _crontab_access() -> bool:
2035+
return (
2036+
subprocess.run(
2037+
["crontab", "-e"],
2038+
env={"VISUAL": "true", "EDITOR": "true"},
2039+
check=False,
2040+
stdout=subprocess.DEVNULL,
2041+
stderr=subprocess.DEVNULL,
2042+
).returncode
2043+
== 0
2044+
)
2045+
2046+
20332047
def main_create(
20342048
version_info: VersionInfo,
20352049
site: SiteContext,
@@ -2215,15 +2229,19 @@ def finalize_site(
22152229

22162230
# avoid executing hook 'TMPFS' and cleaning an initialized tmp directory
22172231
# see CMK-3067
2218-
finalize_site_as_user(
2232+
outcome = finalize_site_as_user(
22192233
version_info, site, command_type, verbose, ignored_hooks=["TMPFS"]
22202234
)
2221-
sys.exit(0)
2235+
sys.exit(outcome.value)
22222236
except Exception as e:
2223-
bail_out("Failed to finalize site: %s" % e)
2237+
sys.stderr.write(f"Failed to finalize site: {e}\n")
2238+
sys.exit(FinalizeOutcome.ABORTED.value)
22242239
else:
22252240
_wpid, status = os.waitpid(pid, 0)
2226-
if status:
2241+
if (
2242+
not os.WIFEXITED(status)
2243+
or (outcome := FinalizeOutcome(os.WEXITSTATUS(status))) is FinalizeOutcome.ABORTED
2244+
):
22272245
bail_out("Error in non-priviledged sub-process.")
22282246

22292247
# The config changes above, made with the site user, have to be also available for
@@ -2241,6 +2259,13 @@ def finalize_site(
22412259
apache_reload,
22422260
verbose=verbose,
22432261
)
2262+
sys.exit(outcome.value)
2263+
2264+
2265+
class FinalizeOutcome(enum.Enum):
2266+
OK = 0
2267+
ABORTED = 1
2268+
WARN = 2
22442269

22452270

22462271
def finalize_site_as_user(
@@ -2249,7 +2274,7 @@ def finalize_site_as_user(
22492274
command_type: CommandType,
22502275
verbose: bool,
22512276
ignored_hooks: Sequence[str],
2252-
) -> None:
2277+
) -> FinalizeOutcome:
22532278
# Mount and create contents of tmpfs. This must be done as normal
22542279
# user. We also could do this at 'omd start', but this might confuse
22552280
# users. They could create files below tmp which would be shadowed
@@ -2270,6 +2295,10 @@ def finalize_site_as_user(
22702295
save_instance_id(file_path=get_instance_id_file_path(Path(site_home)), instance_id=uuid4())
22712296

22722297
call_scripts(site, "post-" + command_type.short, open_pty=sys.stdout.isatty())
2298+
if not _crontab_access():
2299+
sys.stderr.write("Warning: site user cannot access crontab\n")
2300+
return FinalizeOutcome.WARN
2301+
return FinalizeOutcome.OK
22732302

22742303

22752304
def main_rm(

0 commit comments

Comments
 (0)