o add missing dependancy in Makefile
o add branch in Model
o implement backup() method, which is responsible for setting up a git repo and pushing it upstream. The actual "git add+commit" is a responsibility of the syshook config event (todo)

sponsored by : Modirum (https://www.modirum.com/)
This commit is contained in:
Ad Schellevis 2020-10-06 18:00:54 +02:00
parent 23bca983e6
commit c73274fc64
3 changed files with 81 additions and 7 deletions

View file

@ -1,7 +1,7 @@
PLUGIN_NAME= git-backup
PLUGIN_VERSION= 0.1
PLUGIN_COMMENT= Track config changes using git
PLUGIN_MAINTAINER= ad@opnsense.org
PLUGIN_DEVEL= yes
PLUGIN_NAME= git-backup
PLUGIN_VERSION= 0.1
PLUGIN_COMMENT= Track config changes using git
PLUGIN_DEPENDS= git
PLUGIN_MAINTAINER= ad@opnsense.org
.include "../../Mk/plugins.mk"

View file

@ -30,6 +30,7 @@
namespace OPNsense\Backup;
use OPNsense\Core\Backend;
use OPNsense\Core\Config;
use OPNsense\Backup\GitSettings;
@ -59,6 +60,13 @@ class Git extends Base implements IBackupProvider
"help" => gettext("Target location, which defined transport protocol, such as ssh://server/project.git or https://server/project.git."),
"value" => null
],
[
"name" => "branch",
"type" => "text",
"label" => gettext("Branch"),
"help" => gettext("Target branch to push to."),
"value" => null
],
[
"name" => "privkey",
"type" => "textarea",
@ -110,11 +118,73 @@ class Git extends Base implements IBackupProvider
}
/**
* @inheritdoc
* Backup is responsible for initialising the local repo and pusing it to upstream.
* To ensure initial content, we should trigger a 'system event config_changed' which should enforce a
* add + commit in our (newly created) repo.
*
* Since our backup method is also called from the userinterface directly, we should try to prevent the need
* for elevated rights. Since all actions are concentrated within the config directory, we only need read/exec
* access on git. (detaching this further would deviate the implementation from the existing ones)
*
* @return array filelist
*/
public function backup()
{
return ['config.xml'];
$targetdir = "/conf/backup/git";
$git = "/usr/local/bin/git";
$mdl = new GitSettings();
if (!is_dir($targetdir)) {
mkdir($targetdir);
}
if (!is_dir('{$targetdir}/.git')) {
exec("{$git} init {$targetdir}");
}
// XXX: since our git backup is plain text and already contains the private key, it doesn't really matter
// to keep the same key in the git directory (we're not going to push it)
$ident_file = "{$targetdir}/identity";
$privkey = trim(str_replace("\r", "", (string)$mdl->privkey)) . "\n";
file_put_contents($ident_file, $privkey);
chmod("{$targetdir}/identity", 0600);
// When there are unprocessed config backups, flush them out.
(new Backend())->configdRun("system event config_changed");
// configure upstream
exec("cd {$targetdir} && ".
"{$git} config core.sshCommand ".
"\"ssh -i {$ident_file} -o StrictHostKeyChecking=accept-new -o PasswordAuthentication=no\""
);
$url = (string)$mdl->url;
$pos = strpos($url, '//');
// inject credentials in url (either username or username:password, depending on transport)
if (stripos(trim((string)$mdl->$url),'http')) {
$cred = urlencode((string)$mdl->user) . ":" . urlencode((string)$mdl->password);
$url = substr($url,0, $pos+2) . "{$cred}@" . substr($url, $pos+2);
} else {
$url = substr($url,0, $pos+2) . urlencode((string)$mdl->user) . "@" . substr($url, $pos+2);
}
exec("cd {$targetdir} && git remote remove origin");
exec("cd {$targetdir} && git remote add origin ". escapeshellarg($url));
$pushtxt = shell_exec(
"(cd {$targetdir} && git push origin " . escapeshellarg("master:{$mdl->branch}") .
" && echo '__exit_ok__') 2>&1"
);
if (strpos($pushtxt, '__exit_ok__')) {
$error_type = null;
} elseif (strpos($pushtxt, 'Permission denied')) {
$error_type = "authentication failure";
} elseif (strpos($pushtxt, 'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED')) {
$error_type = "ssh hostkey changed";
} elseif (strpos($pushtxt, "remote contains work that you do")) {
$error_type = "git out of sync";
} else {
$error_type = "unknown error, check log for details";
}
if (!empty($error_type)) {
syslog(LOG_ERR, "git-backup {$error_type} (".str_replace("\n", " ", $pushtxt).")");
throw new \Exception($error_type);
} else {
// return filelist in git
return explode("\n", shell_exec("cd {$targetdir} && git ls-files"));
}
}
/**

View file

@ -29,6 +29,10 @@
</check001>
</Constraints>
</url>
<branch type="TextField">
<default>master</default>
<Required>Y</Required>
</branch>
<privkey type="TextField">
<Required>N</Required>
</privkey>