pyinfra 0.11.dev3__py3-none-any.whl → 3.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyinfra/__init__.py +9 -12
- pyinfra/__main__.py +4 -0
- pyinfra/api/__init__.py +19 -3
- pyinfra/api/arguments.py +413 -0
- pyinfra/api/arguments_typed.py +79 -0
- pyinfra/api/command.py +274 -0
- pyinfra/api/config.py +222 -28
- pyinfra/api/connect.py +33 -13
- pyinfra/api/connectors.py +27 -0
- pyinfra/api/deploy.py +65 -66
- pyinfra/api/exceptions.py +73 -18
- pyinfra/api/facts.py +267 -200
- pyinfra/api/host.py +416 -50
- pyinfra/api/inventory.py +121 -160
- pyinfra/api/metadata.py +69 -0
- pyinfra/api/operation.py +432 -262
- pyinfra/api/operations.py +273 -260
- pyinfra/api/state.py +302 -248
- pyinfra/api/util.py +309 -369
- pyinfra/connectors/base.py +173 -0
- pyinfra/connectors/chroot.py +212 -0
- pyinfra/connectors/docker.py +405 -0
- pyinfra/connectors/dockerssh.py +297 -0
- pyinfra/connectors/local.py +238 -0
- pyinfra/connectors/scp/__init__.py +1 -0
- pyinfra/connectors/scp/client.py +204 -0
- pyinfra/connectors/ssh.py +727 -0
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +309 -0
- pyinfra/connectors/sshuserclient/config.py +102 -0
- pyinfra/connectors/terraform.py +135 -0
- pyinfra/connectors/util.py +417 -0
- pyinfra/connectors/vagrant.py +183 -0
- pyinfra/context.py +145 -0
- pyinfra/facts/__init__.py +7 -6
- pyinfra/facts/apk.py +22 -7
- pyinfra/facts/apt.py +117 -60
- pyinfra/facts/brew.py +100 -15
- pyinfra/facts/bsdinit.py +23 -0
- pyinfra/facts/cargo.py +37 -0
- pyinfra/facts/choco.py +47 -0
- pyinfra/facts/crontab.py +195 -0
- pyinfra/facts/deb.py +94 -0
- pyinfra/facts/dnf.py +48 -0
- pyinfra/facts/docker.py +96 -23
- pyinfra/facts/efibootmgr.py +113 -0
- pyinfra/facts/files.py +629 -58
- pyinfra/facts/flatpak.py +77 -0
- pyinfra/facts/freebsd.py +70 -0
- pyinfra/facts/gem.py +19 -6
- pyinfra/facts/git.py +59 -14
- pyinfra/facts/gpg.py +150 -0
- pyinfra/facts/hardware.py +313 -167
- pyinfra/facts/iptables.py +72 -62
- pyinfra/facts/launchd.py +44 -0
- pyinfra/facts/lxd.py +17 -4
- pyinfra/facts/mysql.py +122 -86
- pyinfra/facts/npm.py +17 -9
- pyinfra/facts/openrc.py +71 -0
- pyinfra/facts/opkg.py +246 -0
- pyinfra/facts/pacman.py +50 -7
- pyinfra/facts/pip.py +24 -7
- pyinfra/facts/pipx.py +82 -0
- pyinfra/facts/pkg.py +15 -6
- pyinfra/facts/pkgin.py +35 -0
- pyinfra/facts/podman.py +54 -0
- pyinfra/facts/postgres.py +178 -0
- pyinfra/facts/postgresql.py +6 -147
- pyinfra/facts/rpm.py +105 -0
- pyinfra/facts/runit.py +77 -0
- pyinfra/facts/selinux.py +161 -0
- pyinfra/facts/server.py +762 -285
- pyinfra/facts/snap.py +88 -0
- pyinfra/facts/systemd.py +139 -0
- pyinfra/facts/sysvinit.py +59 -0
- pyinfra/facts/upstart.py +35 -0
- pyinfra/facts/util/__init__.py +17 -0
- pyinfra/facts/util/databases.py +4 -6
- pyinfra/facts/util/packaging.py +37 -6
- pyinfra/facts/util/units.py +30 -0
- pyinfra/facts/util/win_files.py +99 -0
- pyinfra/facts/vzctl.py +20 -13
- pyinfra/facts/xbps.py +35 -0
- pyinfra/facts/yum.py +34 -40
- pyinfra/facts/zfs.py +77 -0
- pyinfra/facts/zypper.py +42 -0
- pyinfra/local.py +45 -83
- pyinfra/operations/__init__.py +12 -0
- pyinfra/operations/apk.py +99 -0
- pyinfra/operations/apt.py +496 -0
- pyinfra/operations/brew.py +232 -0
- pyinfra/operations/bsdinit.py +59 -0
- pyinfra/operations/cargo.py +45 -0
- pyinfra/operations/choco.py +61 -0
- pyinfra/operations/crontab.py +194 -0
- pyinfra/operations/dnf.py +213 -0
- pyinfra/operations/docker.py +492 -0
- pyinfra/operations/files.py +2014 -0
- pyinfra/operations/flatpak.py +95 -0
- pyinfra/operations/freebsd/__init__.py +12 -0
- pyinfra/operations/freebsd/freebsd_update.py +70 -0
- pyinfra/operations/freebsd/pkg.py +219 -0
- pyinfra/operations/freebsd/service.py +116 -0
- pyinfra/operations/freebsd/sysrc.py +92 -0
- pyinfra/operations/gem.py +48 -0
- pyinfra/operations/git.py +420 -0
- pyinfra/operations/iptables.py +312 -0
- pyinfra/operations/launchd.py +45 -0
- pyinfra/operations/lxd.py +69 -0
- pyinfra/operations/mysql.py +610 -0
- pyinfra/operations/npm.py +57 -0
- pyinfra/operations/openrc.py +63 -0
- pyinfra/operations/opkg.py +89 -0
- pyinfra/operations/pacman.py +82 -0
- pyinfra/operations/pip.py +206 -0
- pyinfra/operations/pipx.py +103 -0
- pyinfra/operations/pkg.py +71 -0
- pyinfra/operations/pkgin.py +92 -0
- pyinfra/operations/postgres.py +437 -0
- pyinfra/operations/postgresql.py +30 -0
- pyinfra/operations/puppet.py +41 -0
- pyinfra/operations/python.py +73 -0
- pyinfra/operations/runit.py +184 -0
- pyinfra/operations/selinux.py +190 -0
- pyinfra/operations/server.py +1100 -0
- pyinfra/operations/snap.py +118 -0
- pyinfra/operations/ssh.py +217 -0
- pyinfra/operations/systemd.py +150 -0
- pyinfra/operations/sysvinit.py +142 -0
- pyinfra/operations/upstart.py +68 -0
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/docker.py +407 -0
- pyinfra/operations/util/files.py +247 -0
- pyinfra/operations/util/packaging.py +338 -0
- pyinfra/operations/util/service.py +46 -0
- pyinfra/operations/vzctl.py +137 -0
- pyinfra/operations/xbps.py +78 -0
- pyinfra/operations/yum.py +213 -0
- pyinfra/operations/zfs.py +176 -0
- pyinfra/operations/zypper.py +193 -0
- pyinfra/progress.py +44 -32
- pyinfra/py.typed +0 -0
- pyinfra/version.py +9 -1
- pyinfra-3.6.dist-info/METADATA +142 -0
- pyinfra-3.6.dist-info/RECORD +160 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info}/WHEEL +1 -2
- pyinfra-3.6.dist-info/entry_points.txt +12 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info/licenses}/LICENSE.md +1 -1
- pyinfra_cli/__init__.py +1 -0
- pyinfra_cli/cli.py +793 -0
- pyinfra_cli/commands.py +66 -0
- pyinfra_cli/exceptions.py +155 -65
- pyinfra_cli/inventory.py +233 -89
- pyinfra_cli/log.py +39 -43
- pyinfra_cli/main.py +26 -495
- pyinfra_cli/prints.py +215 -156
- pyinfra_cli/util.py +172 -105
- pyinfra_cli/virtualenv.py +25 -20
- pyinfra/api/connectors/__init__.py +0 -21
- pyinfra/api/connectors/ansible.py +0 -99
- pyinfra/api/connectors/docker.py +0 -178
- pyinfra/api/connectors/local.py +0 -169
- pyinfra/api/connectors/ssh.py +0 -402
- pyinfra/api/connectors/sshuserclient/client.py +0 -105
- pyinfra/api/connectors/sshuserclient/config.py +0 -90
- pyinfra/api/connectors/util.py +0 -63
- pyinfra/api/connectors/vagrant.py +0 -155
- pyinfra/facts/init.py +0 -176
- pyinfra/facts/util/files.py +0 -102
- pyinfra/hook.py +0 -41
- pyinfra/modules/__init__.py +0 -11
- pyinfra/modules/apk.py +0 -64
- pyinfra/modules/apt.py +0 -272
- pyinfra/modules/brew.py +0 -122
- pyinfra/modules/files.py +0 -711
- pyinfra/modules/gem.py +0 -30
- pyinfra/modules/git.py +0 -115
- pyinfra/modules/init.py +0 -344
- pyinfra/modules/iptables.py +0 -271
- pyinfra/modules/lxd.py +0 -45
- pyinfra/modules/mysql.py +0 -347
- pyinfra/modules/npm.py +0 -47
- pyinfra/modules/pacman.py +0 -60
- pyinfra/modules/pip.py +0 -99
- pyinfra/modules/pkg.py +0 -43
- pyinfra/modules/postgresql.py +0 -245
- pyinfra/modules/puppet.py +0 -20
- pyinfra/modules/python.py +0 -37
- pyinfra/modules/server.py +0 -524
- pyinfra/modules/ssh.py +0 -150
- pyinfra/modules/util/files.py +0 -52
- pyinfra/modules/util/packaging.py +0 -118
- pyinfra/modules/vzctl.py +0 -133
- pyinfra/modules/yum.py +0 -171
- pyinfra/pseudo_modules.py +0 -64
- pyinfra-0.11.dev3.dist-info/.DS_Store +0 -0
- pyinfra-0.11.dev3.dist-info/METADATA +0 -135
- pyinfra-0.11.dev3.dist-info/RECORD +0 -95
- pyinfra-0.11.dev3.dist-info/entry_points.txt +0 -3
- pyinfra-0.11.dev3.dist-info/top_level.txt +0 -2
- pyinfra_cli/__main__.py +0 -40
- pyinfra_cli/config.py +0 -92
- /pyinfra/{modules/util → connectors}/__init__.py +0 -0
- /pyinfra/{api/connectors → connectors}/sshuserclient/__init__.py +0 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage runit services.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from pyinfra import host
|
|
10
|
+
from pyinfra.api import operation
|
|
11
|
+
from pyinfra.facts.files import File
|
|
12
|
+
from pyinfra.facts.runit import RunitManaged, RunitStatus
|
|
13
|
+
|
|
14
|
+
from .files import file, link
|
|
15
|
+
from .util.service import handle_service_control
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@operation()
|
|
19
|
+
def service(
|
|
20
|
+
service: str,
|
|
21
|
+
running: bool = True,
|
|
22
|
+
restarted: bool = False,
|
|
23
|
+
reloaded: bool = False,
|
|
24
|
+
command: Optional[str] = None,
|
|
25
|
+
enabled: Optional[bool] = None,
|
|
26
|
+
managed: bool = True,
|
|
27
|
+
svdir: str = "/var/service",
|
|
28
|
+
sourcedir: str = "/etc/sv",
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
Manage the state of runit services.
|
|
32
|
+
|
|
33
|
+
+ service: name of the service to manage
|
|
34
|
+
+ running: whether the service should be running
|
|
35
|
+
+ restarted: whether the service should be restarted
|
|
36
|
+
+ reloaded: whether the service should be reloaded
|
|
37
|
+
+ command: custom command to pass like: ``sv <command> <service>``
|
|
38
|
+
+ enabled: whether this service should be enabled/disabled on boot
|
|
39
|
+
+ managed: whether runit should manage this service
|
|
40
|
+
|
|
41
|
+
For services to be controlled, they first need to be managed by runit by
|
|
42
|
+
adding a symlink to the service in ``SVDIR``.
|
|
43
|
+
By setting ``managed=False`` the symlink will be removed.
|
|
44
|
+
Other options won't have any effect after that.
|
|
45
|
+
Although the ``<service>/down`` file can still be controlled with the
|
|
46
|
+
``enabled`` option.
|
|
47
|
+
|
|
48
|
+
+ svdir: alternative ``SVDIR``
|
|
49
|
+
|
|
50
|
+
An alternative ``SVDIR`` can be specified. This can be used for user services.
|
|
51
|
+
|
|
52
|
+
+ sourcedir: where to search for available services
|
|
53
|
+
|
|
54
|
+
An alternative directory for available services can be specified.
|
|
55
|
+
Example: ``sourcedir=/etc/sv.local`` for services managed by the administrator.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
was_managed = service in host.get_fact(RunitManaged, service=service, svdir=svdir)
|
|
59
|
+
was_auto = not host.get_fact(File, path="{0}/{1}/down".format(sourcedir, service))
|
|
60
|
+
|
|
61
|
+
# Disable autostart for previously unmanaged services.
|
|
62
|
+
#
|
|
63
|
+
# Where ``running=False`` is requested, this prevents one case of briefly
|
|
64
|
+
# starting and stopping the service.
|
|
65
|
+
if not was_managed and managed and was_auto:
|
|
66
|
+
yield from auto._inner(
|
|
67
|
+
service=service,
|
|
68
|
+
auto=False,
|
|
69
|
+
sourcedir=sourcedir,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
yield from manage._inner(
|
|
73
|
+
service=service,
|
|
74
|
+
managed=managed,
|
|
75
|
+
svdir=svdir,
|
|
76
|
+
sourcedir=sourcedir,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Service wasn't managed before, so wait for ``runsv`` to start.
|
|
80
|
+
# ``runsvdir`` will check at least every 5 seconds for new services.
|
|
81
|
+
# Wait for at most 10 seconds for the service to be managed, otherwise fail.
|
|
82
|
+
if not was_managed and managed:
|
|
83
|
+
yield from wait_runsv._inner(
|
|
84
|
+
service=service,
|
|
85
|
+
svdir=svdir,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if isinstance(enabled, bool):
|
|
89
|
+
yield from auto._inner(
|
|
90
|
+
service=service,
|
|
91
|
+
auto=enabled,
|
|
92
|
+
sourcedir=sourcedir,
|
|
93
|
+
)
|
|
94
|
+
else:
|
|
95
|
+
# restore previous state of ``<service>/down``
|
|
96
|
+
yield from auto._inner(
|
|
97
|
+
service=service,
|
|
98
|
+
auto=was_auto,
|
|
99
|
+
sourcedir=sourcedir,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Services need to be managed by ``runit`` for the other options to make sense.
|
|
103
|
+
if not managed:
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
yield from handle_service_control(
|
|
107
|
+
host,
|
|
108
|
+
service,
|
|
109
|
+
host.get_fact(RunitStatus, service=service, svdir=svdir),
|
|
110
|
+
"SVDIR={0} sv {{1}} {{0}}".format(svdir),
|
|
111
|
+
running,
|
|
112
|
+
restarted,
|
|
113
|
+
reloaded,
|
|
114
|
+
command,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@operation()
|
|
119
|
+
def manage(
|
|
120
|
+
service: str,
|
|
121
|
+
managed: bool = True,
|
|
122
|
+
svdir: str = "/var/service",
|
|
123
|
+
sourcedir: str = "/etc/sv",
|
|
124
|
+
):
|
|
125
|
+
"""
|
|
126
|
+
Manage runit svdir links.
|
|
127
|
+
|
|
128
|
+
+ service: name of the service to manage
|
|
129
|
+
+ managed: whether the link should exist
|
|
130
|
+
+ svdir: alternative ``SVDIR``
|
|
131
|
+
+ sourcedir: where to search for available services
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
yield from link._inner(
|
|
135
|
+
path="{0}/{1}".format(svdir, service),
|
|
136
|
+
target="{0}/{1}".format(sourcedir, service),
|
|
137
|
+
present=managed,
|
|
138
|
+
create_remote_dir=False,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@operation(is_idempotent=False)
|
|
143
|
+
def wait_runsv(
|
|
144
|
+
service: str,
|
|
145
|
+
svdir: str = "/var/service",
|
|
146
|
+
timeout: int = 10,
|
|
147
|
+
):
|
|
148
|
+
"""
|
|
149
|
+
Wait for runsv for ``service`` to be available.
|
|
150
|
+
|
|
151
|
+
+ service: name of the service to manage
|
|
152
|
+
+ svdir: alternative ``SVDIR``
|
|
153
|
+
+ timeout: time in seconds to wait
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
yield (
|
|
157
|
+
"export SVDIR={0}\n"
|
|
158
|
+
"for i in $(seq {1}); do\n"
|
|
159
|
+
" sv status {2} > /dev/null && exit 0\n"
|
|
160
|
+
" sleep 1;\n"
|
|
161
|
+
"done\n"
|
|
162
|
+
"exit 1"
|
|
163
|
+
).format(svdir, timeout, service)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@operation()
|
|
167
|
+
def auto(
|
|
168
|
+
service: str,
|
|
169
|
+
auto: bool = True,
|
|
170
|
+
sourcedir: str = "/etc/sv",
|
|
171
|
+
):
|
|
172
|
+
"""
|
|
173
|
+
Start service automatically by managing the ``service/down`` file.
|
|
174
|
+
|
|
175
|
+
+ service: name of the service to manage
|
|
176
|
+
+ auto: whether the service should start automatically
|
|
177
|
+
+ sourcedir: where to search for available services
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
yield from file._inner(
|
|
181
|
+
path="{0}/{1}/down".format(sourcedir, service),
|
|
182
|
+
present=not auto,
|
|
183
|
+
create_remote_dir=False,
|
|
184
|
+
)
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Provides operations to set SELinux file contexts, booleans and port types.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
from pyinfra import host
|
|
10
|
+
from pyinfra.api import OperationValueError, QuoteString, StringCommand, operation
|
|
11
|
+
from pyinfra.facts.selinux import FileContext, FileContextMapping, SEBoolean, SEPort, SEPorts
|
|
12
|
+
from pyinfra.facts.server import Which
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Boolean(Enum):
|
|
16
|
+
ON = "on"
|
|
17
|
+
OFF = "off"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Protocol(Enum):
|
|
21
|
+
UDP = "udp"
|
|
22
|
+
TCP = "tcp"
|
|
23
|
+
SCTP = "sctp"
|
|
24
|
+
DCCP = "dccp"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@operation()
|
|
28
|
+
def boolean(bool_name: str, value: Boolean, persistent=False):
|
|
29
|
+
"""
|
|
30
|
+
Set the specified SELinux boolean to the desired state.
|
|
31
|
+
|
|
32
|
+
+ boolean: name of an SELinux boolean
|
|
33
|
+
+ value: desired state of the boolean
|
|
34
|
+
+ persistent: whether to write updated policy or not
|
|
35
|
+
|
|
36
|
+
Note: This operation requires root privileges.
|
|
37
|
+
|
|
38
|
+
**Example:**
|
|
39
|
+
|
|
40
|
+
.. code:: python
|
|
41
|
+
|
|
42
|
+
from pyinfra.operations import selinux
|
|
43
|
+
selinux.boolean(
|
|
44
|
+
name='Allow Apache to connect to LDAP server',
|
|
45
|
+
'httpd_can_network_connect',
|
|
46
|
+
Boolean.ON,
|
|
47
|
+
persistent=True
|
|
48
|
+
)
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
value_str: str
|
|
52
|
+
if value in ["on", "off"]: # compatibility with the old version
|
|
53
|
+
assert isinstance(value, str)
|
|
54
|
+
value_str = value
|
|
55
|
+
elif value is Boolean.ON:
|
|
56
|
+
value_str = "on"
|
|
57
|
+
elif value is Boolean.OFF:
|
|
58
|
+
value_str = "off"
|
|
59
|
+
else:
|
|
60
|
+
raise OperationValueError(f"Invalid value '{value}' for boolean operation")
|
|
61
|
+
|
|
62
|
+
if host.get_fact(SEBoolean, boolean=bool_name) != value_str:
|
|
63
|
+
persist = "-P " if persistent else ""
|
|
64
|
+
yield StringCommand("setsebool", f"{persist}{bool_name}", value_str)
|
|
65
|
+
else:
|
|
66
|
+
host.noop(f"boolean '{bool_name}' already had the value '{value_str}'")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@operation()
|
|
70
|
+
def file_context(path: str, se_type: str):
|
|
71
|
+
"""
|
|
72
|
+
Set the SELinux type for the specified path to the specified value.
|
|
73
|
+
|
|
74
|
+
+ path: the target path (expression) for the context
|
|
75
|
+
+ se_type: the SELinux type for the given target
|
|
76
|
+
|
|
77
|
+
**Example:**
|
|
78
|
+
|
|
79
|
+
.. code:: python
|
|
80
|
+
|
|
81
|
+
selinux.file_context(
|
|
82
|
+
name='Allow /foo/bar to be served by the web server',
|
|
83
|
+
'/foo/bar',
|
|
84
|
+
'httpd_sys_content_t'
|
|
85
|
+
)
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
current = host.get_fact(FileContext, path=path) or {}
|
|
89
|
+
if se_type != current.get("type", ""):
|
|
90
|
+
yield StringCommand("chcon", "-t", se_type, QuoteString(path))
|
|
91
|
+
else:
|
|
92
|
+
host.noop(f"file_context: '{path}' already had type '{se_type}'")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@operation()
|
|
96
|
+
def file_context_mapping(target: str, se_type: str | None = None, present=True):
|
|
97
|
+
"""
|
|
98
|
+
Set the SELinux file context mapping for paths matching the target.
|
|
99
|
+
|
|
100
|
+
+ target: the target path (expression) for the context
|
|
101
|
+
+ se_type: the SELinux type for the given target
|
|
102
|
+
+ present: whether to add or remove the target -> context mapping
|
|
103
|
+
|
|
104
|
+
Note: `file_context` does not change the SELinux file context for existing files
|
|
105
|
+
so `restorecon` may need to be run manually if the file contexts cannot be created
|
|
106
|
+
before the related files.
|
|
107
|
+
|
|
108
|
+
**Example:**
|
|
109
|
+
|
|
110
|
+
.. code:: python
|
|
111
|
+
|
|
112
|
+
selinux.file_context_mapping(
|
|
113
|
+
name='Allow Apache to serve content from the /web directory',
|
|
114
|
+
r'/web(/.*)?',
|
|
115
|
+
se_type='httpd_sys_content_t'
|
|
116
|
+
)
|
|
117
|
+
"""
|
|
118
|
+
if present and (se_type is None):
|
|
119
|
+
raise ValueError("se_type must have a valid value if present is set")
|
|
120
|
+
|
|
121
|
+
current = host.get_fact(FileContextMapping, target=target)
|
|
122
|
+
if present:
|
|
123
|
+
option = "-a" if len(current) == 0 else ("-m" if current.get("type") != se_type else "")
|
|
124
|
+
if option != "":
|
|
125
|
+
yield StringCommand("semanage", "fcontext", option, "-t", se_type, QuoteString(target))
|
|
126
|
+
else:
|
|
127
|
+
host.noop(f"mapping for '{target}' -> '{se_type}' already present")
|
|
128
|
+
else:
|
|
129
|
+
if len(current) > 0:
|
|
130
|
+
yield StringCommand("semanage", "fcontext", "-d", QuoteString(target))
|
|
131
|
+
else:
|
|
132
|
+
host.noop(f"no existing mapping for '{target}'")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@operation()
|
|
136
|
+
def port(protocol: Protocol | str, port_num: int, se_type: str | None = None, present=True):
|
|
137
|
+
"""
|
|
138
|
+
Set the SELinux type for the specified protocol and port.
|
|
139
|
+
|
|
140
|
+
+ protocol: the protocol: (udp|tcp|sctp|dccp)
|
|
141
|
+
+ port: the port
|
|
142
|
+
+ se_type: the SELinux type for the given port
|
|
143
|
+
+ present: whether to add or remove the SELinux type for the port
|
|
144
|
+
|
|
145
|
+
Note: This operation requires root privileges.
|
|
146
|
+
|
|
147
|
+
**Example:**
|
|
148
|
+
|
|
149
|
+
.. code:: python
|
|
150
|
+
|
|
151
|
+
selinux.port(
|
|
152
|
+
name='Allow Apache to provide service on port 2222',
|
|
153
|
+
Protocol.TCP,
|
|
154
|
+
2222,
|
|
155
|
+
'http_port_t',
|
|
156
|
+
)
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
if protocol is Protocol:
|
|
160
|
+
assert isinstance(protocol, Protocol)
|
|
161
|
+
protocol = protocol.value
|
|
162
|
+
|
|
163
|
+
if present and (se_type is None):
|
|
164
|
+
raise ValueError("se_type must have a valid value if present is set")
|
|
165
|
+
|
|
166
|
+
new_type = se_type if present else ""
|
|
167
|
+
direct_get = len(host.get_fact(Which, command="sepolicy") or "") > 0
|
|
168
|
+
if direct_get:
|
|
169
|
+
current = host.get_fact(SEPort, protocol=protocol, port=port_num)
|
|
170
|
+
else:
|
|
171
|
+
port_info = host.get_fact(SEPorts)
|
|
172
|
+
current = port_info.get(protocol, {}).get(str(port_num), "")
|
|
173
|
+
|
|
174
|
+
if present:
|
|
175
|
+
option = "-a" if current == "" else ("-m" if current != se_type else "")
|
|
176
|
+
if option != "":
|
|
177
|
+
yield StringCommand("semanage", "port", option, "-t", se_type, "-p", protocol, port_num)
|
|
178
|
+
else:
|
|
179
|
+
host.noop(f"setype for '{protocol}/{port_num}' is already '{se_type}'")
|
|
180
|
+
else:
|
|
181
|
+
if current != "":
|
|
182
|
+
yield StringCommand("semanage", "port", "-d", "-p", protocol, port_num)
|
|
183
|
+
else:
|
|
184
|
+
host.noop(f"setype for '{protocol}/{port_num}' is already unset")
|
|
185
|
+
|
|
186
|
+
if (present and (option != "")) or (not present and (current != "")):
|
|
187
|
+
if not direct_get:
|
|
188
|
+
if protocol not in port_info:
|
|
189
|
+
port_info[protocol] = {}
|
|
190
|
+
port_info[protocol][str(port_num)] = new_type
|