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 Jan 2, 2025
1 parent 20459f1 commit 2c53fc5
Show file tree
Hide file tree
Showing 21 changed files with 451 additions and 8 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
20 changes: 19 additions & 1 deletion 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. More Infos [here](#update-token-handling)

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 Expand Up @@ -515,4 +518,19 @@ client.ini.php. **doil** offers a state for this.
```bash
doil apply <instance_name> prevent-super-global-replacement
```
As of **doil** version 20241113, **doil** applies this state independently to newly created instances.
As of **doil** version 20241113, **doil** applies this state independently to newly created instances.

### Update Token Handling
Doil instances can be updated via token. There is an entry for this in setup/doil.conf. By default, this entry
is set to 'false' and thus prevents the feature from being activated. To activate the feature once, the value
must be adjusted and then a doil update must be run.
Once the feature has been activated, the token can be updated subsequently using the following command:
```bash
doil sut -t <token>
```
If the feature is active and the token is set up, an update command can be sent via the URL http://doil/<instance>/update.
The currently checked out branch is updated. A 'composer install' and an 'php setup update' are then carried out.
It is important that the Http header contains the field 'Authorization:<token>'. A curl command might look like this.
```bash
curl -H "Authorization:MyToken" http://doil/<instance>/update -L
```
2 changes: 1 addition & 1 deletion app/src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class App extends Application
{
const NAME = "Doil Version 20241205 - build 2024-12-05";
const NAME = "Doil Version 20250102 - build 2025-01-02";

public function __construct(Command ...$commands)
{
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
18 changes: 18 additions & 0 deletions app/src/Commands/Instances/CreateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ public function execute(InputInterface $input, OutputInterface $output) : int
$keycloak = true;
}

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

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

if (isset($options["repo_path"]) && ! $this->filesystem->exists($options["repo_path"])) {
Expand Down Expand Up @@ -324,6 +326,10 @@ public function execute(InputInterface $input, OutputInterface $output) : int
sleep(1);
$this->docker->setGrain($instance_salt_name, "cpass", "$cron_password");
sleep(1);
if ($update_token != "false") {
$this->docker->setGrain($instance_salt_name, "update_token", "${$update_token}");
sleep(1);
}
$this->docker->setGrain($instance_salt_name, "doil_domain", $http_scheme . $host . "/" . $options["name"]);
sleep(1);
$this->docker->setGrain($instance_salt_name, "doil_project_name", $options["name"]);
Expand Down Expand Up @@ -388,6 +394,18 @@ public function execute(InputInterface $input, OutputInterface $output) : int
$this->writer->endBlock();
}

if ($update_token != "false") {
// 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
158 changes: 158 additions & 0 deletions app/src/Commands/Instances/SetUpdateTokenCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?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\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")
->addOption("autoyes", "a", InputOption::VALUE_NONE, "Auto answer questions with yes")
;
}

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;
}

if (! $input->getOption("autoyes")) {
$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): void
{
$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();
}
}
23 changes: 21 additions & 2 deletions app/src/Commands/Pack/PackCreateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ public function execute(InputInterface $input, OutputInterface $output) : int
if ($this->filesystem->exists(self::KEYCLOAK_PATH)) {
$keycloak = true;
}
$update_token = explode("=", $this->filesystem->getLineInFile("/etc/doil/doil.conf", "update_token="))[1];

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

Expand Down Expand Up @@ -319,9 +320,15 @@ 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);
if ($update_token != "false") {
$this->docker->setGrain($instance_salt_name, "update_token", "${update_token}");
sleep(1);
}
$doil_domain = $http_scheme . $host . "/" . $options["name"];
$this->docker->setGrain($instance_salt_name, "doil_domain", "${doil_domain}");
sleep(1);
Expand Down Expand Up @@ -367,10 +374,22 @@ 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));
$this->writer->endBlock();

if ($update_token != "false") {
// 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
$this->writer->beginBlock($output, "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
10 changes: 7 additions & 3 deletions app/tests/Commands/Instances/CreateCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,14 @@ public function test_execute() : void
->willReturn(false, true, false, true)
;
$filesystem
->expects($this->exactly(2))
->expects($this->exactly(3))
->method("getLineInFile")
->withConsecutive(["/etc/doil/doil.conf", "host="], ["/etc/doil/doil.conf", "https_proxy="])
->willReturnOnConsecutiveCalls("foo=doil", "foo=false")
->withConsecutive(
["/etc/doil/doil.conf", "host="],
["/etc/doil/doil.conf", "https_proxy="],
["/etc/doil/doil.conf", "update_token="]
)
->willReturnOnConsecutiveCalls("foo=doil", "foo=false", "update_token=false")
;
$filesystem
->expects($this->once())
Expand Down
1 change: 1 addition & 0 deletions setup/conf/doil.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ keycloak_new_admin_password=admin
keycloak_old_admin_password=admin
keycloak_db_username=admin
keycloak_db_password=admin
update_token=DasToken
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
Loading

0 comments on commit 2c53fc5

Please sign in to comment.