mirror of
https://github.com/Froxlor/Froxlor.git
synced 2024-09-21 10:27:29 +00:00
add CLI install command (more testing tbd)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
parent
f3b277237e
commit
d545e7e09d
@ -32,6 +32,7 @@ use Froxlor\Cli\ConfigServices;
|
||||
use Froxlor\Cli\PhpSessionclean;
|
||||
use Froxlor\Cli\SwitchServerIp;
|
||||
use Froxlor\Cli\UpdateCommand;
|
||||
use Froxlor\Cli\InstallCommand;
|
||||
use Froxlor\Froxlor;
|
||||
|
||||
// validate correct php version
|
||||
@ -53,4 +54,5 @@ $application->add(new ConfigServices());
|
||||
$application->add(new PhpSessionclean());
|
||||
$application->add(new SwitchServerIp());
|
||||
$application->add(new UpdateCommand());
|
||||
$application->add(new InstallCommand());
|
||||
$application->run();
|
||||
|
195
lib/Froxlor/Cli/InstallCommand.php
Normal file
195
lib/Froxlor/Cli/InstallCommand.php
Normal file
@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you can also view it online at
|
||||
* https://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright the authors
|
||||
* @author Froxlor team <team@froxlor.org>
|
||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||
*/
|
||||
|
||||
namespace Froxlor\Cli;
|
||||
|
||||
use Exception;
|
||||
use Froxlor\Froxlor;
|
||||
use Froxlor\Install\Install;
|
||||
use Froxlor\Install\Install\Core;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
final class InstallCommand extends Command
|
||||
{
|
||||
|
||||
private $io = null;
|
||||
|
||||
private $formfielddata = [];
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('froxlor:install');
|
||||
$this->setDescription('Installation process to use instead of web-ui');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$result = self::SUCCESS;
|
||||
|
||||
if (file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) {
|
||||
$output->writeln("<error>froxlor seems to be installed already.</>");
|
||||
return self::INVALID;
|
||||
}
|
||||
|
||||
require __DIR__ . '/install.functions.php';
|
||||
|
||||
$this->io = new SymfonyStyle($input, $output);
|
||||
|
||||
$this->io->title('Froxlor installation');
|
||||
|
||||
$extended = $this->io->confirm('Use advanced installation mode?', false);
|
||||
|
||||
// set a few defaults CLI cannot know
|
||||
$_SERVER['SERVER_SOFTWARE'] = 'apache';
|
||||
$host = [];
|
||||
exec('hostname -f', $host);
|
||||
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
|
||||
$ips = [];
|
||||
exec('hostname -I', $ips);
|
||||
$ips = explode(" ", $ips[0]);
|
||||
// ipv4 address?
|
||||
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
|
||||
if (empty($_SERVER['SERVER_ADDR'])) {
|
||||
// possible ipv6 address?
|
||||
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? ($ips[0] ?? '') : '';
|
||||
}
|
||||
|
||||
$result = $this->showStep(0, $extended);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function showStep(int $step = 0, bool $extended = false): int
|
||||
{
|
||||
$result = self::SUCCESS;
|
||||
$inst = new Install(['step' => $step, 'extended' => $extended]);
|
||||
switch ($step) {
|
||||
case 0:
|
||||
$this->io->section(lng('install.preflight'));
|
||||
$crresult = $inst->checkRequirements();
|
||||
$this->io->info($crresult['text']);
|
||||
if (!empty($crresult['criticals'])) {
|
||||
foreach ($crresult['criticals'] as $ctype => $critical) {
|
||||
if (!empty($ctype) && $ctype == 'wrong_ownership') {
|
||||
$this->io->error(lng('install.errors.' . $ctype, [$critical['user'], $critical['group']]));
|
||||
} elseif (!empty($ctype) && $ctype == 'missing_extensions') {
|
||||
$this->io->error([
|
||||
lng('install.errors.' . $ctype),
|
||||
implode("\n", $critical)
|
||||
]);
|
||||
} else {
|
||||
$this->io->error($critical);
|
||||
}
|
||||
}
|
||||
$result = self::FAILURE;
|
||||
}
|
||||
if (!empty($crresult['suggestions'])) {
|
||||
foreach ($crresult['suggestions'] as $ctype => $suggestion) {
|
||||
if ($ctype == 'missing_extensions') {
|
||||
$this->io->warning([
|
||||
lng('install.errors.suggestedextensions'),
|
||||
implode("\n", $suggestion)
|
||||
]);
|
||||
} else {
|
||||
$this->io->warning($suggestion);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($result == self::SUCCESS && $this->io->confirm('Continue?', true)) {
|
||||
return $this->showStep(++$step, $extended);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
$section = $inst->formfield['install']['sections']['step' . $step] ?? [];
|
||||
$this->io->section($section['title']);
|
||||
$this->io->note($section['description']);
|
||||
foreach ($section['fields'] as $fieldname => $fielddata) {
|
||||
if ($extended == false && isset($fielddata['advanced']) && $fielddata['advanced'] == true) {
|
||||
continue;
|
||||
}
|
||||
$fielddata['value'] = $this->formfielddata[$fieldname] ?? ($fielddata['value'] ?? null);
|
||||
$fielddata['label'] = strip_tags(str_replace("<br>", " ", $fielddata['label']));
|
||||
if ($fielddata['type'] == 'password') {
|
||||
$this->formfielddata[$fieldname] = $this->io->askHidden($fielddata['label'], function ($value) use ($fielddata) {
|
||||
if (isset($fielddata['mandatory']) && $fielddata['mandatory'] && empty($value)) {
|
||||
throw new \RuntimeException('You must enter a value.');
|
||||
}
|
||||
return $value;
|
||||
});
|
||||
} elseif ($fielddata['type'] == 'checkbox') {
|
||||
$this->formfielddata[$fieldname] = $this->io->confirm($fielddata['label'], $fielddata['value'] ?? false);
|
||||
} elseif ($fielddata['type'] == 'select') {
|
||||
$this->formfielddata[$fieldname] = $this->io->choice($fielddata['label'], $fielddata['select_var'], $fielddata['selected'] ?? '');
|
||||
} else {
|
||||
$this->formfielddata[$fieldname] = $this->io->ask($fielddata['label'], $fielddata['value'] ?? '', function ($value) use ($fielddata) {
|
||||
if (isset($fielddata['mandatory']) && $fielddata['mandatory'] && empty($value)) {
|
||||
throw new \RuntimeException('You must enter a value.');
|
||||
}
|
||||
return $value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if ($step == 1) {
|
||||
// $inst->checkDatabase($this->formfielddata);
|
||||
} elseif ($step == 2) {
|
||||
// $inst->checkAdminUser($this->formfielddata);
|
||||
} elseif ($step == 3) {
|
||||
// $inst->checkSystem($this->formfielddata);
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$this->io->error($e->getMessage());
|
||||
return $this->showStep($step, $extended);
|
||||
}
|
||||
return $this->showStep(++$step, $extended);
|
||||
break;
|
||||
case 4:
|
||||
// do actual install with data from $this->formfielddata
|
||||
// $core = new Core($this->formfielddata);
|
||||
// $core->doInstall();
|
||||
$section = $inst->formfield['install']['sections']['step' . $step] ?? [];
|
||||
$this->io->section($section['title']);
|
||||
$this->io->note($section['description']);
|
||||
$cmdfield = $section['fields']['system'];
|
||||
$this->io->success([
|
||||
$cmdfield['label'],
|
||||
$cmdfield['value']
|
||||
]);
|
||||
if ($this->io->confirm('Execute command now?', false)) {
|
||||
exec($cmdfield['value']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
36
lib/Froxlor/Cli/install.functions.php
Normal file
36
lib/Froxlor/Cli/install.functions.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you can also view it online at
|
||||
* https://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright the authors
|
||||
* @author Froxlor team <team@froxlor.org>
|
||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||
*/
|
||||
|
||||
use Froxlor\Language;
|
||||
|
||||
function lng(string $identifier, array $arguments = [])
|
||||
{
|
||||
return Language::getTranslation($identifier, $arguments);
|
||||
}
|
||||
|
||||
function old(string $identifier, string $default = null, string $session = null)
|
||||
{
|
||||
return $default;
|
||||
}
|
@ -54,7 +54,7 @@ class Install
|
||||
'mod_php' => 'mod_php (not recommended)',
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
public function __construct(array $cliData = [])
|
||||
{
|
||||
// get all supported OS
|
||||
// show list of available distro's
|
||||
@ -78,28 +78,30 @@ class Install
|
||||
$this->formfield = require dirname(__DIR__, 3) . '/lib/formfields/install/formfield.install.php';
|
||||
|
||||
// set actual step
|
||||
$this->currentStep = Request::get('step', 0);
|
||||
$this->extendedView = Request::get('extended', 0);
|
||||
$this->currentStep = $cliData['step'] ?? Request::get('step', 0);
|
||||
$this->extendedView = $cliData['extended'] ?? Request::get('extended', 0);
|
||||
$this->maxSteps = count($this->formfield['install']['sections']);
|
||||
|
||||
// set actual php version and extensions
|
||||
$this->phpVersion = phpversion();
|
||||
$this->loadedExtensions = get_loaded_extensions();
|
||||
|
||||
// set global variables
|
||||
UI::twig()->addGlobal('install_mode', true);
|
||||
UI::twig()->addGlobal('basehref', '../');
|
||||
if (empty($cliData)) {
|
||||
// set global variables
|
||||
UI::twig()->addGlobal('install_mode', true);
|
||||
UI::twig()->addGlobal('basehref', '../');
|
||||
|
||||
// unset session if user goes back to step 0
|
||||
if (isset($_SESSION['installation']) && $this->currentStep == 0) {
|
||||
unset($_SESSION['installation']);
|
||||
}
|
||||
// unset session if user goes back to step 0
|
||||
if (isset($_SESSION['installation']) && $this->currentStep == 0) {
|
||||
unset($_SESSION['installation']);
|
||||
}
|
||||
|
||||
// check for url manipulation or wrong step
|
||||
if ((isset($_SESSION['installation']['stepCompleted']) && ($this->currentStep + 1) > ($_SESSION['installation']['stepCompleted'] ?? 0))
|
||||
|| (!isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > 0)
|
||||
) {
|
||||
$this->currentStep = isset($_SESSION['installation']['stepCompleted']) ? $_SESSION['installation']['stepCompleted'] + 1 : 1;
|
||||
// check for url manipulation or wrong step
|
||||
if ((isset($_SESSION['installation']['stepCompleted']) && ($this->currentStep + 1) > ($_SESSION['installation']['stepCompleted'] ?? 0))
|
||||
|| (!isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > 0)
|
||||
) {
|
||||
$this->currentStep = isset($_SESSION['installation']['stepCompleted']) ? $_SESSION['installation']['stepCompleted'] + 1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,7 +208,7 @@ class Install
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function checkRequirements(): array
|
||||
public function checkRequirements(): array
|
||||
{
|
||||
// check whether we can read the userdata file
|
||||
if (!@touch(dirname(__DIR__, 2) . '/.~writecheck')) {
|
||||
@ -286,7 +288,7 @@ class Install
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function checkSystem(array $validatedData): void
|
||||
public function checkSystem(array $validatedData): void
|
||||
{
|
||||
$serveripv4 = $validatedData['serveripv4'] ?? '';
|
||||
$serveripv6 = $validatedData['serveripv6'] ?? '';
|
||||
@ -312,7 +314,7 @@ class Install
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function checkAdminUser(array $validatedData): void
|
||||
public function checkAdminUser(array $validatedData): void
|
||||
{
|
||||
$name = $validatedData['admin_name'] ?? 'Administrator';
|
||||
$loginname = $validatedData['admin_user'] ?? '';
|
||||
@ -336,7 +338,7 @@ class Install
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function checkDatabase(array $validatedData): void
|
||||
public function checkDatabase(array $validatedData): void
|
||||
{
|
||||
$dsn = sprintf('mysql:host=%s;charset=utf8', $validatedData['mysql_host']);
|
||||
$pdo = new \PDO($dsn, $validatedData['mysql_root_user'], $validatedData['mysql_root_pass']);
|
||||
@ -384,7 +386,7 @@ class Install
|
||||
|
||||
private function guessWebserver(): ?string
|
||||
{
|
||||
if (strtoupper(@php_sapi_name()) == "APACHE2HANDLER" || stristr($_SERVER['SERVER_SOFTWARE'], "apache/2")) {
|
||||
if (strtoupper(@php_sapi_name()) == "APACHE2HANDLER" || stristr($_SERVER['SERVER_SOFTWARE'], "apache")) {
|
||||
return 'apache24';
|
||||
} elseif (substr(strtoupper(@php_sapi_name()), 0, 8) == "LIGHTTPD" || stristr($_SERVER['SERVER_SOFTWARE'], "lighttpd")) {
|
||||
return 'lighttpd';
|
||||
@ -397,14 +399,13 @@ class Install
|
||||
private function guessDistribution(): ?string
|
||||
{
|
||||
// set default os.
|
||||
$os_dist = array(
|
||||
'VERSION_CODENAME' => 'bullseye'
|
||||
);
|
||||
$default = 'bullseye';
|
||||
|
||||
// read os-release
|
||||
if (@file_exists('/etc/os-release')) {
|
||||
$os_dist = parse_ini_file('/etc/os-release', false);
|
||||
return strtolower($os_dist['VERSION_CODENAME'] ?? ($os_dist['ID'] ?? null));
|
||||
return strtolower($os_dist['VERSION_CODENAME'] ?? ($os_dist['ID'] ?? $default));
|
||||
}
|
||||
return null;
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ return [
|
||||
'type' => 'select',
|
||||
'mandatory' => true,
|
||||
'select_var' => ['apache24' => 'Apache 2.4', 'nginx' => 'Nginx', 'lighttpd' => 'LigHTTPd'],
|
||||
'value' => old('webserver', $guessedWebserver, 'installation'),
|
||||
'selected' => old('webserver', $guessedWebserver, 'installation'),
|
||||
],
|
||||
'webserver_backend' => [
|
||||
'label' => lng('install.system.phpbackend'),
|
||||
|
Loading…
Reference in New Issue
Block a user