Skip to content

Commit 0fcb6e8

Browse files
committed
18146 omd create: Distinguish failures by exit status
SUP-24001 Change-Id: Ibe3b21e80881c8f922dee9337279116067118b82
1 parent c503726 commit 0fcb6e8

2 files changed

Lines changed: 57 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.4.0p7
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: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import abc
1111
import contextlib
12+
import enum
1213
import errno
1314
import fcntl
1415
import io
@@ -2034,6 +2035,19 @@ def use_update_alternatives() -> bool:
20342035
return os.path.exists("/var/lib/dpkg/alternatives/omd")
20352036

20362037

2038+
def _crontab_access() -> bool:
2039+
return (
2040+
subprocess.run(
2041+
["crontab", "-e"],
2042+
env={"VISUAL": "true", "EDITOR": "true"},
2043+
check=False,
2044+
stdout=subprocess.DEVNULL,
2045+
stderr=subprocess.DEVNULL,
2046+
).returncode
2047+
== 0
2048+
)
2049+
2050+
20372051
def main_create(
20382052
version_info: VersionInfo,
20392053
site: SiteContext,
@@ -2218,13 +2232,19 @@ def finalize_site(
22182232

22192233
# avoid executing hook 'TMPFS' and cleaning an initialized tmp directory
22202234
# see CMK-3067
2221-
finalize_site_as_user(version_info, site, command_type, ignored_hooks=["TMPFS"])
2222-
sys.exit(0)
2235+
outcome = finalize_site_as_user(
2236+
version_info, site, command_type, ignored_hooks=["TMPFS"]
2237+
)
2238+
sys.exit(outcome.value)
22232239
except Exception as e:
2224-
bail_out("Failed to finalize site: %s" % e)
2240+
sys.stderr.write(f"Failed to finalize site: {e}\n")
2241+
sys.exit(FinalizeOutcome.ABORTED.value)
22252242
else:
22262243
_wpid, status = os.waitpid(pid, 0)
2227-
if status:
2244+
if (
2245+
not os.WIFEXITED(status)
2246+
or (outcome := FinalizeOutcome(os.WEXITSTATUS(status))) is FinalizeOutcome.ABORTED
2247+
):
22282248
bail_out("Error in non-priviledged sub-process.")
22292249

22302250
# The config changes above, made with the site user, have to be also available for
@@ -2241,14 +2261,21 @@ def finalize_site(
22412261
apache_reload,
22422262
verbose=verbose,
22432263
)
2264+
sys.exit(outcome.value)
2265+
2266+
2267+
class FinalizeOutcome(enum.Enum):
2268+
OK = 0
2269+
ABORTED = 1
2270+
WARN = 2
22442271

22452272

22462273
def finalize_site_as_user(
22472274
version_info: VersionInfo,
22482275
site: SiteContext,
22492276
command_type: CommandType,
22502277
ignored_hooks: list[str] | None = None,
2251-
) -> None:
2278+
) -> FinalizeOutcome:
22522279
# Mount and create contents of tmpfs. This must be done as normal
22532280
# user. We also could do this at 'omd start', but this might confuse
22542281
# users. They could create files below tmp which would be shadowed
@@ -2268,6 +2295,10 @@ def finalize_site_as_user(
22682295
save_instance_id(file_path=get_instance_id_file_path(Path(site.dir)), instance_id=uuid4())
22692296

22702297
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
22712302

22722303

22732304
def main_rm(

0 commit comments

Comments
 (0)