Skip to content

Commit 1839ceb

Browse files
author
Kristan Kenney
committed
Merge branch 'master' of https://github.com/hestiacp/hestiacp
2 parents 239e12a + 6817571 commit 1839ceb

File tree

1 file changed

+293
-0
lines changed

1 file changed

+293
-0
lines changed

test/make-test-containers.php

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
#
5+
# Auto create multiple Hesia containers with various features enabled/disabled
6+
# lxc/lxd should be allready configured
7+
# - container name will be generated depending on enabled features (os,proxy,webserver and php)
8+
# - 'SHARED_HOST_FOLDER' will be mounted in the (guest lxc) container at '/home/ubuntu/source/' and hestiacp src folder is expected to be there
9+
# - wildcard dns *.hst.domain.tld can be used to point to vm host
10+
# - watch install log ex:(host) tail -n 100 -f /tmp/hst_installer_hst-ub1604-a2-mphp
11+
#
12+
# CONFIG HOST STEPS:
13+
# export SHARED_HOST_FOLDER="/home/myuser/projectfiles"
14+
# mkdir -p $SHARED_HOST_FOLDER
15+
# cd $SHARED_HOST_FOLDER && git clone https://github.com/hestiacp/hestiacp.git && cd hestiacp && git checkout ..branch..
16+
#
17+
18+
/*
19+
# Nginx reverse proxy config: /etc/nginx/conf.d/lxc-hestia.conf
20+
server {
21+
listen 80;
22+
server_name ~(?<lxcname>hst-.+)\.hst\.domain\.tld$;
23+
location / {
24+
set $backend_upstream "http://$lxcname:80";
25+
proxy_pass $backend_upstream;
26+
proxy_set_header Host $host;
27+
proxy_set_header X-Forwarded-For $remote_addr;
28+
}
29+
}
30+
server {
31+
listen 8083;
32+
server_name ~^(?<lxcname>hst-.+)\.hst\.domain\.tld$;
33+
location / {
34+
set $backend_upstream "https://$lxcname:8083";
35+
proxy_pass $backend_upstream;
36+
}
37+
}
38+
39+
# use lxc resolver /etc/nginx/nginx.conf
40+
# test resolver ip ex: dig +short @10.240.232.1 hst-ub1804-ngx-a2-mphp
41+
http {
42+
...
43+
resolver 10.240.232.1 ipv6=off valid=5s;
44+
...
45+
}
46+
47+
*/
48+
49+
## Uncomment and configure the following vars
50+
# define('DOMAIN', 'hst.domain.tld');
51+
# define('SHARED_HOST_FOLDER', '/home/myuser/projectfiles');
52+
# define('HST_PASS', ''); // <- # openssl rand -base64 12
53+
# define('HST_EMAIL', 'user@domain.tld');
54+
define('HST_BRANCH', '~localsrc');
55+
define('HST_ARGS', '--force --interactive no --clamav no -p ' . HST_PASS . ' --email ' . HST_EMAIL);
56+
define('LXC_TIMEOUT', 15);
57+
58+
if( !defined('SHARED_HOST_FOLDER') || !defined('HST_PASS') || !defined('HST_EMAIL') || !defined('HST_BRANCH') || !defined('DOMAIN') ) {
59+
die("Error: missing variables".PHP_EOL);
60+
}
61+
62+
$containers = [
63+
// ['description'=>'hst-d9-ngx-a2-mphp', 'os'=>'debian9', 'nginx'=>true, 'apache2'=>true, 'php'=>'multiphp', 'dns'=>'auto', 'exim'=>'auto'],
64+
['description'=>'ub1804 ngx mphp', 'os'=>'ubuntu18.04', 'nginx'=>true, 'apache2'=>false, 'php'=>'multiphp', 'dns'=>'auto', 'exim'=>'auto'],
65+
['description'=>'ub1804 ngx fpm', 'os'=>'ubuntu18.04', 'nginx'=>true, 'apache2'=>false, 'php'=>'fpm', 'dns'=>'auto', 'exim'=>'auto'],
66+
['description'=>'ub1804 ngx a2', 'os'=>'ubuntu18.04', 'nginx'=>true, 'apache2'=>true, 'php'=>'auto', 'dns'=>'auto', 'exim'=>'auto'],
67+
['description'=>'ub1804 ngx a2 mphp', 'os'=>'ubuntu18.04', 'nginx'=>true, 'apache2'=>true, 'php'=>'multiphp', 'dns'=>'auto', 'exim'=>'auto'],
68+
['description'=>'ub1804 a2 mphp', 'os'=>'ubuntu18.04', 'nginx'=>false, 'apache2'=>true, 'php'=>'multiphp', 'dns'=>'auto', 'exim'=>'auto'],
69+
['description'=>'ub1804 a2', 'os'=>'ubuntu18.04', 'nginx'=>false, 'apache2'=>true, 'php'=>'auto', 'dns'=>'auto'],
70+
['description'=>'ub1604 a2 mphp', 'os'=>'ubuntu16.04', 'nginx'=>false, 'apache2'=>true, 'php'=>'multiphp', 'dns'=>'auto', 'exim'=>'auto'],
71+
];
72+
73+
array_walk($containers, function(&$element) {
74+
$lxc_name='hst-'; // hostname and lxc name prefix. Update nginx reverse proxy config after altering this value
75+
$hst_args = HST_ARGS;
76+
77+
$element['hst_installer'] = 'hst-install-ubuntu.sh';
78+
$element['lxc_image'] = 'ubuntu:18.04';
79+
80+
if($element['os'] == "ubuntu16.04") {
81+
$element['lxc_image'] = 'ubuntu:16.04';
82+
$lxc_name .= 'ub1604';
83+
} else if($element['os'] == "debian8") {
84+
$element['lxc_image'] = 'images:debian/8';
85+
$element['hst_installer'] = 'hst-install-debian.sh';
86+
$lxc_name .= 'd8';
87+
} else if($element['os'] == "debian9") {
88+
$element['lxc_image'] = 'images:debian/9';
89+
$element['hst_installer'] = 'hst-install-debian.sh';
90+
$lxc_name .= 'd9';
91+
} else {
92+
$lxc_name .= 'ub1804';
93+
$element['os'] = "ubuntu18.04";
94+
}
95+
96+
if($element['nginx'] === true) {
97+
$lxc_name .= '-ngx';
98+
$hst_args .= " --nginx yes";
99+
} else
100+
$hst_args .= " --nginx no";
101+
102+
if($element['apache2'] === true) {
103+
$lxc_name .= '-a2';
104+
$hst_args .= " --apache yes";
105+
} else
106+
$hst_args .= " --apache no";
107+
108+
109+
if($element['php'] == 'fpm') {
110+
$lxc_name .= '-fpm';
111+
$hst_args .= " --phpfpm yes";
112+
} else if($element['php'] == 'multiphp') {
113+
$lxc_name .= '-mphp';
114+
$hst_args .= " --multiphp yes";
115+
}
116+
117+
if(isset($element['dns'])) {
118+
if($element['dns'] === true || $element['dns'] == 'auto') {
119+
$hst_args .= " --named yes";
120+
} else {
121+
$hst_args .= " --named no";
122+
}
123+
}
124+
125+
if(isset($element['exim'])) {
126+
if($element['exim'] === true || $element['exim'] == 'auto') {
127+
$hst_args .= " --exim yes";
128+
} else {
129+
$hst_args .= " --exim no";
130+
}
131+
}
132+
133+
if(isset($element['webmail'])) {
134+
if($element['webmail'] === true || $element['webmail'] == 'auto') {
135+
$hst_args .= " --dovecot yes";
136+
} else {
137+
$hst_args .= " --dovecot no";
138+
}
139+
}
140+
141+
$element['lxc_name'] = $lxc_name;
142+
$element['hostname'] = $lxc_name . '.' . DOMAIN;
143+
144+
// $hst_args .= ' --with-debs /home/ubuntu/source/hestiacp/src/pkgs/develop/' . $element['os'];
145+
$hst_args .= ' --with-debs /tmp/hestiacp-src/debs';
146+
$hst_args .= ' --hostname ' . $element['hostname'];
147+
$element['hst_args'] = $hst_args;
148+
});
149+
150+
function lxc_run($args, &$rc) {
151+
$cmd_args = "";
152+
153+
if(is_array($args)) {
154+
foreach ($args as $arg) {
155+
$cmd_args .= ' ' . escapeshellarg($arg);
156+
}
157+
} else
158+
$cmd_args = $args;
159+
160+
exec('lxc ' . $cmd_args . ' 2>/dev/null', $cmdout, $rc);
161+
162+
if(isset($rc) && $rc !== 0)
163+
return false;
164+
165+
if(json_decode(implode(PHP_EOL, $cmdout),true) === null)
166+
return $cmdout;
167+
168+
return json_decode(implode(PHP_EOL, $cmdout),true);
169+
}
170+
171+
function getHestiaVersion($branch) {
172+
$control_file = '';
173+
if($branch==='~localsrc')
174+
$control_file = file_get_contents(SHARED_HOST_FOLDER . '/hestiacp/src/deb/hestia/control');
175+
else {
176+
$control_file = file_get_contents("https://raw.githubusercontent.com/hestiacp/hestiacp/${branch}/src/deb/hestia/control");
177+
}
178+
179+
foreach(explode(PHP_EOL, $control_file) as $line) {
180+
if(empty($line))
181+
continue;
182+
183+
list($key,$value) = explode(':', $line);
184+
if(strtolower($key) === 'version')
185+
return trim($value);
186+
}
187+
188+
throw new Exception("Error reading Hestia version for branch: [${branch}]", 1);
189+
}
190+
191+
function get_lxc_ip($name) {
192+
$result = lxc_run(['list', '--format', 'csv', '-c', 'n,4'],$rc);
193+
if(empty($result))
194+
return false;
195+
196+
foreach ($result as $line) {
197+
list($cnt, $address) = explode(',', $line);
198+
if($cnt == $name) {
199+
$iface = explode(' ', $address);
200+
if(filter_var($iface[0], FILTER_VALIDATE_IP))
201+
return $iface[0];
202+
else
203+
return false;
204+
}
205+
}
206+
}
207+
208+
function check_lxc_container($container) {
209+
echo "Check container:".$container['lxc_name'].PHP_EOL;
210+
211+
lxc_run(['info', $container['lxc_name']], $rc);
212+
if(isset($rc) && $rc === 0)
213+
return;
214+
215+
echo "Creating container ".$container['lxc_name'] . PHP_EOL;
216+
lxc_run(['init', $container['lxc_image'], $container['lxc_name']], $rc);
217+
exec('lxc config set '.escapeshellarg($container['lxc_name']).' raw.idmap "both 1000 1000" 2>/dev/null', $devnull, $rc);
218+
exec('lxc config device add '.escapeshellarg($container['lxc_name']).' hestiasrc disk path=/home/ubuntu/source source='.SHARED_HOST_FOLDER.' 2>/dev/null', $devnull, $rc);
219+
lxc_run(['start', $container['lxc_name']], $rc);
220+
221+
$lxc_retry = 0;
222+
do {
223+
$lxc_retry++;
224+
$cip = get_lxc_ip($container['lxc_name']);
225+
if($cip)
226+
echo "container ip: $cip" . PHP_EOL;
227+
sleep(1);
228+
} while ($lxc_retry <= LXC_TIMEOUT && filter_var($cip, FILTER_VALIDATE_IP) === false);
229+
230+
echo "Updating container: " . $container['lxc_name'] . PHP_EOL;
231+
exec('lxc exec ' . $container['lxc_name'] . ' -- apt update', $devnull, $rc);
232+
}
233+
234+
function hst_installer_worker($container) {
235+
$pid = pcntl_fork();
236+
if($pid > 0)
237+
return $pid;
238+
239+
system( 'lxc exec '.$container['lxc_name'].' -- bash -c "/home/ubuntu/source/hestiacp/src/hst_autocompile.sh --hestia \"'.HST_BRANCH.'\" no"');
240+
241+
$hver = getHestiaVersion(HST_BRANCH);
242+
echo "Install Hestia ${hver} on " . $container['lxc_name'] . PHP_EOL;
243+
echo "Args: " . $container['hst_args'] . PHP_EOL;
244+
245+
system( 'lxc exec '.$container['lxc_name'].' -- bash -c "cd \"/home/ubuntu/source/hestiacp\"; install/'.$container['hst_installer'].
246+
' '.$container['hst_args'].'" 2>&1 > /tmp/hst_installer_'.$container['lxc_name']);
247+
248+
exit(0);
249+
}
250+
251+
$worker_pool = [];
252+
foreach ($containers as $container) {
253+
check_lxc_container($container);
254+
255+
# Is hestia installed?
256+
lxc_run('exec '.$container['lxc_name'].' -- sudo --login "v-list-sys-config"', $rc);
257+
if(isset($rc) && $rc===0)
258+
continue;
259+
260+
$worker_pid = hst_installer_worker($container);
261+
if($worker_pid > 0)
262+
$worker_pool[] = $worker_pid;
263+
}
264+
265+
echo count($worker_pool) . " background workers started" . PHP_EOL;
266+
267+
# waiting for workers to finish
268+
while(count($worker_pool)) {
269+
echo "Wait for workers to finish".PHP_EOL;
270+
$child_pid = pcntl_wait($status);
271+
if($child_pid) {
272+
$worker_pos = array_search($child_pid, $worker_pool);
273+
unset($worker_pool[$worker_pos]);
274+
}
275+
}
276+
277+
foreach ($containers as $container) {
278+
echo "Apply custom config on: ".$container['lxc_name'].PHP_EOL;
279+
280+
# Allow running a reverse proxy in front of Hestia
281+
system( 'lxc exec '.$container['lxc_name'].' -- bash -c "sed -i \'s/session.cookie_secure] = on\$/session.cookie_secure] = off/\' /usr/local/hestia/php/etc/php-fpm.conf"');
282+
283+
# get rid off "mesg: ttyname failed: No such device" error
284+
system( 'lxc exec '.$container['lxc_name'].' -- bash -c "sed -i -re \'s/^(mesg n)(.*)$/#\1\2/g\' /root/.profile"');
285+
286+
# Use LE sandbox server, prevents hitting rate limits
287+
system( 'lxc exec '.$container['lxc_name'].' -- bash -c "sed -i \'/LE_STAGING/d\' /usr/local/hestia/conf/hestia.conf"');
288+
system( 'lxc exec '.$container['lxc_name'].' -- bash -c "echo \'LE_STAGING=\"YES\"\' >> /usr/local/hestia/conf/hestia.conf"');
289+
290+
system( 'lxc exec '.$container['lxc_name'].' -- bash -c "service hestia restart"');
291+
}
292+
293+
echo "Hestia containers configured".PHP_EOL;

0 commit comments

Comments
 (0)