xref: /unit/test/unit/check/isolation.py (revision 2616:ab2896c980ab)
1import json
2from pathlib import Path
3
4from unit.applications.lang.go import ApplicationGo
5from unit.applications.lang.java import ApplicationJava
6from unit.applications.lang.node import ApplicationNode
7from unit.applications.lang.ruby import ApplicationRuby
8from unit.http import HTTP1
9from unit.option import option
10from unit.utils import getns
11
12allns = ['pid', 'mnt', 'ipc', 'uts', 'cgroup', 'net']
13http = HTTP1()
14
15
16def check_isolation():
17    available = option.available
18
19    conf = ''
20    if 'go' in available['modules']:
21        ApplicationGo().prepare_env('empty', 'app')
22
23        conf = {
24            "listeners": {"*:8080": {"pass": "applications/empty"}},
25            "applications": {
26                "empty": {
27                    "type": "external",
28                    "processes": {"spare": 0},
29                    "working_directory": f"{option.test_dir}/go/empty",
30                    "executable": f"{option.test_dir}/go/app",
31                    "isolation": {"namespaces": {"credential": True}},
32                },
33            },
34        }
35
36    elif 'python' in available['modules']:
37        conf = {
38            "listeners": {"*:8080": {"pass": "applications/empty"}},
39            "applications": {
40                "empty": {
41                    "type": "python",
42                    "processes": {"spare": 0},
43                    "path": f"{option.test_dir}/python/empty",
44                    "working_directory": f"{option.test_dir}/python/empty",
45                    "module": "wsgi",
46                    "isolation": {"namespaces": {"credential": True}},
47                }
48            },
49        }
50
51    elif 'php' in available['modules']:
52        conf = {
53            "listeners": {"*:8080": {"pass": "applications/phpinfo"}},
54            "applications": {
55                "phpinfo": {
56                    "type": "php",
57                    "processes": {"spare": 0},
58                    "root": f"{option.test_dir}/php/phpinfo",
59                    "working_directory": f"{option.test_dir}/php/phpinfo",
60                    "index": "index.php",
61                    "isolation": {"namespaces": {"credential": True}},
62                }
63            },
64        }
65
66    elif 'ruby' in available['modules']:
67        ApplicationRuby().prepare_env('empty')
68
69        conf = {
70            "listeners": {"*:8080": {"pass": "applications/empty"}},
71            "applications": {
72                "empty": {
73                    "type": "ruby",
74                    "processes": {"spare": 0},
75                    "working_directory": f"{option.temp_dir}/ruby/empty",
76                    "script": f"{option.temp_dir}/ruby/empty/config.ru",
77                    "isolation": {"namespaces": {"credential": True}},
78                }
79            },
80        }
81
82    elif 'java' in available['modules']:
83        ApplicationJava().prepare_env('empty')
84
85        conf = {
86            "listeners": {"*:8080": {"pass": "applications/empty"}},
87            "applications": {
88                "empty": {
89                    "unit_jars": f"{option.current_dir}/build",
90                    "type": "java",
91                    "processes": {"spare": 0},
92                    "working_directory": f"{option.temp_dir}/java/empty/",
93                    "webapp": f"{option.temp_dir}/java",
94                    "isolation": {"namespaces": {"credential": True}},
95                }
96            },
97        }
98
99    elif 'node' in available['modules']:
100        ApplicationNode().prepare_env('basic')
101
102        conf = {
103            "listeners": {"*:8080": {"pass": "applications/basic"}},
104            "applications": {
105                "basic": {
106                    "type": "external",
107                    "processes": {"spare": 0},
108                    "working_directory": f"{option.temp_dir}/node",
109                    "executable": "app.js",
110                    "isolation": {"namespaces": {"credential": True}},
111                }
112            },
113        }
114
115    elif 'perl' in available['modules']:
116        conf = {
117            "listeners": {"*:8080": {"pass": "applications/body_empty"}},
118            "applications": {
119                "body_empty": {
120                    "type": "perl",
121                    "processes": {"spare": 0},
122                    "working_directory": f"{option.test_dir}/perl/body_empty",
123                    "script": f"{option.test_dir}/perl/body_empty/psgi.pl",
124                    "isolation": {"namespaces": {"credential": True}},
125                }
126            },
127        }
128
129    else:
130        return False
131
132    resp = http.put(
133        url='/config',
134        sock_type='unix',
135        addr=f'{option.temp_dir}/control.unit.sock',
136        body=json.dumps(conf),
137    )
138
139    if 'success' not in resp['body']:
140        return False
141
142    userns = getns('user')
143    if not userns:
144        return False
145
146    isolation = {'user': userns}
147
148    path_clone = Path('/proc/sys/kernel/unprivileged_userns_clone')
149    if (
150        path_clone.exists()
151        and path_clone.read_text(encoding='utf-8').rstrip() == '1'
152    ):
153        isolation['unprivileged_userns_clone'] = True
154
155    for ns in allns:
156        ns_value = getns(ns)
157        if ns_value:
158            isolation[ns] = ns_value
159
160    return isolation
161