Skip to content

Commit

Permalink
master states:442 distribute update token, and enable doil to trigger
Browse files Browse the repository at this point in the history
instance updates via url
  • Loading branch information
daniwe4 committed Dec 9, 2024
1 parent af2e730 commit 214cc35
Show file tree
Hide file tree
Showing 20 changed files with 399 additions and 7 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@
* better salt key handling
* !! Attention: doil needs to be reinstalled !!

## 20240617
## What's Changes
* update of an instance can now be triggered by url

## 20240604
## What's Changed
* CSP Rules per instance

## 20240422
## What's Changed
* fix typo in apache 000-default
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ The following commands are available:
* `doil delete <instance_name>` deletes an instance you do not need anymore
* `doil status` lists the current running doil instances
* `doil exec <instance_name> <cmd>` executes a bash command inside the instance
* `doil sut` (alias for `doil instances:set-update-token`) Sets an update token as an environment variable. This is cross-checked during instance updates via the browser

See `doil instances:<command> --help` for more information

Expand Down Expand Up @@ -180,6 +181,8 @@ Following commands come with the `--global` flag:
* `doil instances:path`
* `doil instances:login`
* `doil instances:exec`
* `doil instances:csp`
* `doil instance:set-update-token`

**`doil repo`**
* `doil repo:add`
Expand Down
4 changes: 3 additions & 1 deletion app/src/Commands/Instances/ApplyCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ class ApplyCommand extends Command
"change-roundcube-password",
"nodejs",
"proxy-enable-https",
"keycloak"
"keycloak",
"ilias-update-hook",
"set-update-token"
];

protected static $defaultName = "instances:apply";
Expand Down
17 changes: 17 additions & 0 deletions app/src/Commands/Instances/CreateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ public function execute(InputInterface $input, OutputInterface $output) : int
$keycloak = true;
}

$update_token = $this->filesystem->getLineInFile("/etc/doil/doil.conf", "update_token");

$this->writer->beginBlock($output, "Creating instance " . $options['name']);

if (isset($options["repo_path"]) && ! $this->filesystem->exists($options["repo_path"])) {
Expand Down Expand Up @@ -319,6 +321,11 @@ public function execute(InputInterface $input, OutputInterface $output) : int
sleep(1);
$this->docker->setGrain($instance_salt_name, "cpass", "$cron_password");
sleep(1);
if (!is_null($update_token)) {
$token = explode("=", $update_token);
$this->docker->setGrain($instance_salt_name, "update_token", "${token[1]}");
sleep(1);
}
$this->docker->setGrain($instance_salt_name, "doil_domain", "http://" . $host . "/" . $options["name"]);
sleep(1);
$this->docker->setGrain($instance_salt_name, "doil_project_name", $options["name"]);
Expand Down Expand Up @@ -383,6 +390,16 @@ public function execute(InputInterface $input, OutputInterface $output) : int
$this->writer->endBlock();
}

// apply set-update-token state
$this->writer->beginBlock($output, "Apply set-update-token state");
$this->docker->applyState($instance_salt_name, "set-update-token");
$this->writer->endBlock();

// apply ilias-update-hook state
$this->writer->beginBlock($output, "Apply ilias-update-hook state");
$this->docker->applyState($instance_salt_name, "ilias-update-hook");
$this->writer->endBlock();

// apply access state
$this->writer->beginBlock($output, "Apply access state");
$this->docker->applyState($instance_salt_name, "access");
Expand Down
155 changes: 155 additions & 0 deletions app/src/Commands/Instances/SetUpdateTokenCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php declare(strict_types=1);

/* Copyright (c) 2022 - Daniel Weise <[email protected]> - Extended GPL, see LICENSE */

namespace CaT\Doil\Commands\Instances;

use CaT\Doil\Lib\Posix\Posix;
use CaT\Doil\Lib\Docker\Docker;
use CaT\Doil\Lib\ConsoleOutput\Writer;
use CaT\Doil\Lib\FileSystem\Filesystem;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Exception\InvalidArgumentException;

class SetUpdateTokenCommand extends Command
{
protected static $defaultName = "instances:set-update-token";
protected static $defaultDescription =
"<fg=red>!NEEDS SUDO PRIVILEGES!</> This command sets a update token for all instances"
;

protected Docker $docker;
protected Posix $posix;
protected Filesystem $filesystem;
protected Writer $writer;

public function __construct(Docker $docker, Posix $posix, Filesystem $filesystem, Writer $writer)
{
parent::__construct();

$this->docker = $docker;
$this->posix = $posix;
$this->filesystem = $filesystem;
$this->writer = $writer;
}

public function configure() : void
{
$this
->setAliases(["sut"])
->addOption("token", "t", InputOption::VALUE_REQUIRED, "Update token as string")
->addOption("global", "g", InputOption::VALUE_NONE, "Determines if an instance is global or not")
;
}

public function execute(InputInterface $input, OutputInterface $output) : int
{
if (! $this->posix->isSudo()) {
$this->writer->error(
$output,
"Please execute this script as sudo user!"
);
return Command::FAILURE;
}

$token = $input->getOption("token");

$home_dir = $this->posix->getHomeDirectory($this->posix->getUserId());

$path = "/usr/local/share/doil/instances";
$suffix = "global";
if (! $input->getOption("global")) {
$path = "$home_dir/.doil/instances";
$suffix = "local";
}

$instances = $this->filesystem->getFilesInPath($path);
if (count($instances) == 0) {
$this->writer->error(
$output,
"No instances found!",
"Use <fg=gray>doil instances:ls --help</> for more information."
);
return Command::FAILURE;
}

$question = new ConfirmationQuestion(
"This will also update 'update_token' in your doil config. Want to continue? [yN]: ",
false
);

$helper = $this->getHelper("question");
if (!$helper->ask($input, $output, $question)) {
$output->writeln("Abort by user!");
return Command::FAILURE;
}

$this->filesystem->replaceLineInFile("/etc/doil/doil.conf", "/update_token=.*/", "update_token=" . $token);

foreach ($instances as $i) {
$started = $this->startInstance($output, $path, $i);
sleep(3);
$this->applyUpdateToken($output, $i . "." . $suffix, $token);
$this->docker->commit($i . "_" . $suffix);
if ($started) {
$this->stopInstance($output, $path, $i);
}
}
return Command::SUCCESS;
}

protected function startInstance(OutputInterface $output, string $path, string $instance) : bool
{
if (! $this->hasDockerComposeFile($path . "/" . $instance, $output)) {
throw new InvalidArgumentException("Can't find a suitable docker-compose.yml file in $path/$instance");
}

if (! $this->docker->isInstanceUp($path . "/" . $instance)) {
$this->writer->beginBlock($output, "Start instance $instance");
$this->docker->startContainerByDockerCompose($path . "/" . $instance);
$this->writer->endBlock();
return true;
}

return false;
}

protected function stopInstance(OutputInterface $output, string $path, string $instance) : string
{
if ($this->docker->isInstanceUp($path . "/" . $instance)) {
$this->writer->beginBlock($output, "Stop instance $instance");
$this->docker->stopContainerByDockerCompose($path . "/" . $instance);
$this->writer->endBlock();
}

return $instance;
}

protected function hasDockerComposeFile(string $path, OutputInterface $output) : bool
{
if ($this->filesystem->exists($path . "/docker-compose.yml")) {
return true;
}

$output->writeln("<fg=red>Error:</>");
$output->writeln("\tCan't find a suitable docker-compose file in this directory '$path'.");
$output->writeln("\tIs this the right directory?");
$output->writeln("\tSupported filenames: docker-compose.yml");

return false;
}

protected function applyUpdateToken(OutputInterface $output, string $salt_key, string $token)
{
$this->writer->beginBlock($output, "Apply update token to $salt_key");
$this->docker->setGrain($salt_key, "update_token", $token);
$this->docker->refreshGrains($salt_key);
$this->docker->applyState($salt_key, "set-update-token");
$this->writer->endBlock();
}
}
22 changes: 20 additions & 2 deletions app/src/Commands/Pack/PackCreateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ public function execute(InputInterface $input, OutputInterface $output) : int
if ($this->filesystem->exists(self::KEYCLOAK_PATH)) {
$keycloak = true;
}
$update_token = $this->filesystem->getLineInFile("/etc/doil/doil.conf", "update_token");

$this->writer->beginBlock($output, "Creating instance " . $options['name']);

Expand Down Expand Up @@ -314,10 +315,17 @@ public function execute(InputInterface $input, OutputInterface $output) : int
}

$this->docker->setGrain($instance_salt_name, "mpass", "${mysql_password}");
$host = explode("=", $this->filesystem->getLineInFile("/etc/doil/doil.conf", "host"));

sleep(1);
$this->docker->setGrain($instance_salt_name, "cpass", "${cron_password}");
$this->docker->setGrain($instance_salt_name, "cpass", "$cron_password");
sleep(1);
$doil_domain = "http://" . $host . "/" . $options["name"];
if (!is_null($update_token)) {
$token = explode("=", $update_token);
$this->docker->setGrain($instance_salt_name, "update_token", "${token[1]}");
sleep(1);
}
$doil_domain = "http://" . $host[1] . "/" . $options["name"];
$this->docker->setGrain($instance_salt_name, "doil_domain", "${doil_domain}");
sleep(1);
$this->docker->setGrain($instance_salt_name, "doil_project_name", "${options['name']}");
Expand Down Expand Up @@ -362,9 +370,19 @@ public function execute(InputInterface $input, OutputInterface $output) : int
$this->writer->endBlock();
}


// apply composer state
$this->writer->beginBlock($output, "Apply composer state");
$this->docker->applyState($instance_salt_name, $this->getComposerVersion($ilias_version));

// apply set-update-token state
$this->writer->beginBlock($output, "Apply set-update-token state");
$this->docker->applyState($instance_salt_name, "set-update-token");
$this->writer->endBlock();

// apply ilias-update-hook state
$this->writer->beginBlock($output, "Apply ilias-update-hook state");
$this->docker->applyState($instance_salt_name, "ilias-update-hook");
$this->writer->endBlock();

// apply enable-captainhook state
Expand Down
10 changes: 10 additions & 0 deletions app/src/cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function buildContainerForApp() : Container
$c["command.instances.login"],
$c["command.instances.path"],
$c["command.instances.restart"],
$c["command.instances.set.update.token"],
$c["command.instances.status"],
$c["command.instances.up"],
$c["command.keycloak.down"],
Expand Down Expand Up @@ -240,6 +241,15 @@ function buildContainerForApp() : Container
);
};

$c["command.instances.set.update.token"] = function($c) {
return new Instances\SetUpdateTokenCommand(
$c["docker.shell"],
$c["posix.shell"],
$c["filesystem.shell"],
$c["command.writer"]
);
};

$c["command.instances.status"] = function($c) {
return new Instances\StatusCommand(
$c["docker.shell"]
Expand Down
6 changes: 3 additions & 3 deletions app/tests/Commands/Instances/CreateCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,10 @@ public function test_execute() : void
->willReturn(false, true, false, true)
;
$filesystem
->expects($this->once())
->expects($this->exactly(2))
->method("getLineInFile")
->with("/etc/doil/doil.conf", "host")
->willReturnOnConsecutiveCalls("foo=doil", "7.8")
->withConsecutive(["/etc/doil/doil.conf", "host"], ["/etc/doil/doil.conf", "update_token"])
->willReturnOnConsecutiveCalls("foo=doil", "update_token=foobar")
;
$filesystem
->expects($this->once())
Expand Down
2 changes: 1 addition & 1 deletion setup/conf/doil.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ keycloak_hostname=http://doil/keycloak
keycloak_new_admin_password=admin
keycloak_old_admin_password=admin
keycloak_db_username=admin
keycloak_db_password=admin
keycloak_db_password=admin
4 changes: 4 additions & 0 deletions setup/stack/config/master.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,8 @@ file_roots:
- /srv/salt/states/ilias
keycloak:
- /srv/salt/states/keycloak
ilias-update-hook:
- /srv/salt/states/ilias-update-hook
compile-skins:
- /srv/salt/states/compile-skins
composer:
Expand Down Expand Up @@ -720,6 +722,8 @@ file_roots:
- /srv/salt/states/disable-saml
prevent-super-global-replacement:
- /srv/salt/states/prevent-super-global-replacement
set-update-token:
- /srv/salt/states/set-update-token


# The master_roots setting configures a master-only copy of the file_roots dictionary,
Expand Down
1 change: 1 addition & 0 deletions setup/stack/states/ilias-update-hook/description.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
description = Inject an update hook file into docroot
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% set ilias_version = salt['grains.get']('ilias_version', '8.0') %}

/var/www/html/.update_hook.php:
file.managed:
- source: salt://ilias-update-hook/update_hook.php.j2
- template: jinja
- context:
ilias_version: {{ ilias_version }}
Loading

0 comments on commit 214cc35

Please sign in to comment.