From 26b7ba2ea68e7da82d426d51c31ce3f256582218 Mon Sep 17 00:00:00 2001 From: Tracey Clark Date: Mon, 11 Sep 2023 19:52:45 -0500 Subject: [PATCH] Initial commit on forgejo --- .gitignore | 13 ++ backup-gitea-bin.pl | 44 +++++ update-gitea.pl | 416 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 473 insertions(+) create mode 100644 .gitignore create mode 100755 backup-gitea-bin.pl create mode 100755 update-gitea.pl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de6a3b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +**/.vscode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix diff --git a/backup-gitea-bin.pl b/backup-gitea-bin.pl new file mode 100755 index 0000000..eb106d6 --- /dev/null +++ b/backup-gitea-bin.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl + +# backup_gitea_bin.pl +# Author: Tracey Clark +# Created: 2019-06-20 +# You must have a mail transport agent installed to run this script + +use strict; +use warnings; + +### TEST CODE ### +my $gitea_bin='/home/tracey/tmp/testbin'; +my $gitea_current_version='1'; +my %binary_file = ( + input => $gitea_bin, + version => $gitea_current_version, + ); + my ( %opts ) = %binary_file; + my $input = $opts{input}; + my $version = $opts{version}; + my $gitea_bin_backup = '/home/tracey/tmp/testbin.' . $gitea_current_version . '.bz2'; + +### TEST CODE ### +# my ( %opts ) = %{shift()}; +# my $input = $opts{input}; +# my $version = $opts{version}; +printf("Backing up the current binary\n"); +printf("Input in backup_bin script is $input\n and version is $version\n"); + + +# my $gitea_bin_backup = '/home/gitea/bin/gitea.' . $gitea_current_version . '.bz2'; +printf("Gitea bin backup will be $gitea_bin_backup\n"); +# Do this with a system call to make a compressed copy of the current binary +# bzip2 -k file.txt +# my $status = system("vi", "fred.txt"); +# if (($status >>=8) != 0) { +# die "Failed to run vi"; +# } + +# HEREHERE how to specify output file?? +my $bzip_status = system("/bin/bzip2 -k $input"); +if (($bzip_status >>=8) != 0) { + die "Failed to run bzip2"; +} diff --git a/update-gitea.pl b/update-gitea.pl new file mode 100755 index 0000000..d8cd101 --- /dev/null +++ b/update-gitea.pl @@ -0,0 +1,416 @@ +#!/usr/bin/perl + +# Update gitea based on version provided +# Author: Tracey Clark +# Created: 2019-03-04 +# You must have a mail transport agent installed to run this script + +# Note: Daily backups are also being run from cron +# /home/gitea/gitea_backup.sh + +# Re-write to use this dir according to gitea docs +# https://docs.gitea.io/en-us/install-from-binary/ +# Get binary from system rather than hard code +# Stop gitea with systemctl before file copy +# Set right mod & perms? + +use strict; +use warnings; +use LWP::UserAgent; +use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error); +use File::Basename; +use JSON; +use Sort::Versions; +use Getopt::Long qw(GetOptions); +use Term::ANSIColor qw(:constants); +use feature qw(say); +use MIME::Lite; +use utf8; +use open ':std', ':encoding(UTF-8)'; +use Encode qw(encode encode_utf8 ); +# use Net::SSH qw(sshopen2); +use Capture::Tiny qw(capture); + +my ( $verbose, $info ); + +GetOptions( + 'info!' => \$info, + 'verbose!' => \$verbose, +); + +########################################## +### The user must set these variables ### +my $email = 'gitea-update@tlcnet.info'; +my $filetype = '-linux-amd64'; +my $download_dir = '/home/gitea/bin/'; +########################################## + +my $update_needed = 0; + +################################### +# Get version currently installed # +################################### +# https://api.github.com/repos/go-gitea/gitea/releases/latest +# This URL will only have one version listed +my $gitea_bin_dir = '/usr/local/bin/'; +my $gitea_bin = $gitea_bin_dir . '/gitea'; +my $gitea_current_version_string = `$gitea_bin --version`; +my $alphanum_ver = 0; +chomp $gitea_current_version_string; +unless ( defined $gitea_current_version_string ) { + my $status = "❌ [DIE]: Unable to get the version of the gitea binary on the system: $!"; + notification('failed ❌', $status); + die RED "$status", RESET; +} +my %binary_file = get_current_binary($gitea_current_version_string); +my $gitea_current_version = $binary_file{'version'}; + +###################################### +# Check upstream version and get tag # +###################################### +my $baseURL = q{https://github.com/go-gitea/gitea/}; +my $latestURL = q{https://api.github.com/repos/go-gitea/gitea/releases/latest}; + +# https://hubpages.com/technology/Use-Perl-to-access-REST-API +# Spin up the browser object +my $ua = LWP::UserAgent->new( + cookie_jar => {}, # keep cookies in RAM but not persistent between sessions +); + +my $resp = $ua->get($latestURL); +my $latest_release_hash = decode_json( $resp->content ) + or die "[DIE]: Unable to parse the version data! Output is:\n $resp"; + +my $orig_tag = $latest_release_hash->{tag_name}; +print "[TLC DEBUG]: ORIG TAG is $orig_tag\n" if defined $verbose; +my $tag = $orig_tag; +substr( $tag, 0, 1, '' ); +my $release_id = $latest_release_hash->{id}; # Works + +################ +# Set filename # +################ +my $unz_filename = 'gitea-' . $tag . $filetype; +#ex: gitea-1.7.6-linux-amd64 +my $download_filename = $unz_filename . '.xz'; + +if ( defined $verbose ) { + printf( YELLOW + "[INFO] Latest upstream version: $tag\n Release ID $release_id\n", RESET); + printf( YELLOW + "[INFO]\nRelease id: $release_id\nUncompressed filename: $unz_filename\nDownload file target: $download_filename\n", RESET + ); +} + +############################################# +# Check if upstream is newer than installed # +############################################# +if ( versioncmp( $gitea_current_version, $tag ) == -1 ) { + $update_needed = 1; + printf( + "[INFO] Version tag is greater than the system version, proceeding with update\n" + ); + backup_bin( \%binary_file ); + + my $download_url = get_download_url( $download_filename, $release_id ); + print("Downloading the compressed binary\n"); + print("[INFO] Download URL we got from the sub is $download_url\n"); + `wget -P $download_dir $download_url`; + my $xz_file = $download_dir . $download_filename; + + if ( defined $info ) { + print YELLOW "[INFO] xz file is $xz_file\n", RESET; + } + install_bin($download_filename); +} + +################################## +# Get service status and version # +################################## +my ($gitea_status, $gitea_proc_status, $gitea_ssh_status) = check_gitea_status(); +$gitea_current_version_string = `$gitea_bin --version`; +chomp $gitea_current_version_string; +%binary_file = get_current_binary($gitea_current_version_string); +$gitea_current_version = $binary_file{'version'}; + +if ( $gitea_status ) { + print( GREEN "[INFO] ✅ Gitea service is active\n", RESET ); +} +else { + print( RED "[ERROR] ❌ Gitea service is NOT active\nProcess: $gitea_proc_status\nSSH: $gitea_ssh_status\n", RESET ); +} + +######################## +# Notify appropriately # +######################## +if ( !$update_needed && $gitea_status ) { + my $status = '✅ Version tag upstream matches the system version, no update needed. Service is running.'; + print( YELLOW "[INFO] $status\nInstalled version: $gitea_current_version\nUpstream version: $tag\n", RESET ); + notification('not needed ✅', $status, $gitea_current_version, $tag); + exit 1; +} +elsif ( $update_needed && versioncmp( $gitea_current_version, $tag ) == -1 ) { + my $status = '❌ Upstream version tag is STILL greater than the current system version after attempting to update, something went wrong'; + notification('failed ❌', $status, $gitea_current_version, $tag); + print( RED $status, RESET ); +} +elsif ( $update_needed && $gitea_status ) { + my $status = '✅ [INFO] Gitea successfuly updated. Installed version is current and service is running'; + print( GREEN "[INFO] $status\n", RESET ); + say "Removing the downloaded xz file and uncompressed file"; + system("rm -vf " . $download_dir . $unz_filename); + system("rm -vf " . $download_dir . $download_filename); + notification('succeeded ✅', $status, $gitea_current_version, $tag); + # Intentionally *not* removing the 'gitea' binary in case something goes wrong running the current binary. +} +elsif ( !$gitea_status ) { + my $status = q{❌ [DIE] The gitea service is no good!

+ Process: } . $gitea_proc_status . q{

+ SSH Output:
} . $gitea_ssh_status . q{
}; + notification('failed ❌', $status, $gitea_current_version, $tag); + die '❌ [DIE] The gitea service is no good!'; +} +else { + my $status = '❌ [DIE] Unknown update status!'; + print( RED $status, RESET ); + notification('failed ❌', $status, $gitea_current_version, $tag); + die $status; +} + +# ##### Subroutines ##### + +# sub check_deps { +# # Check to make sure dependencies installed on system - unit test?? +# # bzip2 perl mods +# } + +sub get_current_binary { + my $current_version_string = shift; + my $current_version; + if ( $current_version_string =~ m/ion\ (\d+\.\d+\.\d*)\s+b/ ) { + $current_version = $1; + printf("Version number of the installed gitea binary: $1\n") if defined $verbose; + } + elsif ( $current_version_string =~ m/ion\ (\d+\d+\w*)\s/ ) { + $current_version = $1; + printf("Current version number the installed gitea binary: $1\n"); + $alphanum_ver = 1; + } + my %binary_file = ( + input => $gitea_bin, + version => $current_version, + ); + unless ( defined $current_version ) { + die RED + "[DIE]: Unable to get the current gitea version! Value is $current_version", + RESET; + } + return %binary_file; +} + +sub get_binary_file { + my $version = shift; +} + +sub backup_bin { + + # Ghetto to get it working for now + + my (%opts) = %{ shift() }; + my $input = $opts{input}; + my $version = $opts{version}; + print GREEN "Backing up the current binary\n", RESET; + if ( defined $info ) { + print YELLOW + "[INFO] Input in backup_bin sub is:\n Directory $input\n Version $version\n", + RESET; + } + my $gitea_bin_backup = + '/home/gitea/bin/gitea.' . $gitea_current_version . '.bz2'; + print GREEN "Gitea bin backup will be $gitea_bin_backup\n", RESET; + system("cp $input $input.bak"); + + # TODO + # # Do this with a system call to make a compressed copy of the current binary + # # bzip2 -k file.txt + # # my $status = system("vi", "fred.txt"); + # # if (($status >>=8) != 0) { + # # die "[DIE] Failed to run vi"; + # # } + # my $bzip_status = system("bzip2 -k", "$input"); + # if (($status >>=8) != 0) { + # die "[DIE] Failed to run bzip2"; + # } + + return; +} + +sub get_download_url { + my ( $dl_filename, $rel_id ) = @_; + my $dl_url; + + # Get the download_url from the array + my $assetsURL = + 'https://api.github.com/repos/go-gitea/gitea/releases/' + . $release_id + . '/assets'; + if ( defined $info ) { + print YELLOW "[INFO] Assets URL\n"; + print "$assetsURL\n", RESET; + } + + my $asset_resp = $ua->get($assetsURL); + my $asset_resp_array_ref = decode_json( $asset_resp->content ); + + if ( defined $verbose ) { + printf( RED + "[DEBUG] Array of hashes of the json response for the assets:\n" + ); + printf Dumper($asset_resp_array_ref), RESET; + } + + foreach my $asset_ref ( @{$asset_resp_array_ref} ) { + if ( defined $verbose ) { + print( RED + "[DEBUG] The asset ref in get_download_url is $asset_ref\n" ); + print( + "The asset ref name in get_download_url is $asset_ref->{name}\n", + RESET + ); + } + if ( $asset_ref->{name} eq $dl_filename ) { + print("Yay we have a match for our desired file :D and it is \n"); + print $asset_ref->{name} . "\n"; + $dl_url = $asset_ref->{browser_download_url}; + if ( defined $info ) { + print YELLOW + "[INFO] The download url from the response array is $dl_url\n", + RESET; + } + return $dl_url; + } + } + unless ( defined $dl_url ) { + print( RED + "ONOES we have no download URL from the github API! Trying to build one manually\n", + RESET + ); + my $dl_url = build_download_url( $orig_tag, $download_filename ); + return $dl_url; + } + return 0; +} + +sub build_download_url { + my ( $url_tag, $url_file ) = @_; + print "Building the URL based on the version\n"; + +# If getting the download URL fails through the API, use this to build it manually +# URL is in the form of +# https://github.com/go-gitea/gitea/releases/download/v1.15.2/gitea-1.15.2-linux-amd64.xz + my $built_url = + 'https://github.com/go-gitea/gitea/releases/download/' + . $url_tag . '/' + . $url_file; + if ( defined $info ) { + print YELLOW "The URL built for the download is $built_url\n", RESET; + } + return $built_url; +} + +sub install_bin { + my $filename = shift; + print("Unpacking the downloaded file \"$download_dir$filename\", setting owner and permissions\n"); + my $unpacked_filename = basename($filename, ".xz"); + print "Unpacked filename is $unpacked_filename\n"; + + # Copy the downloaded binary to gitea and chmod it 750 + # Doing this with a filthy system call because the perl library + # for xz manipulation is a memory hog and buggy besides + system("xz -d --keep $download_dir" . "/" . "$filename"); + system("systemctl stop gitea"); + system("cp $download_dir$unpacked_filename $gitea_bin"); + system("chown gitea.gitea $gitea_bin"); + system("chmod 750 $gitea_bin"); + + # Restart service + print("[INFO] Restarting the gitea service\n"); + return system("systemctl restart gitea"); +} + +sub check_gitea_status { + my $gitea_status; + my $gitea_proc_status = `systemctl is-active gitea`; + sleep 1; # Otherwise the SSH regex doesnt work; + + my $command = 'ssh -i /home/tracey/.ssh/id_tlc_gitea gitea'; + # DEBUG - induce failure + # my $command = 'ssh -i /home/tracey/.ssh/blerg gitea'; + my ($out, $err, $exit) = capture { system $command }; + + # print "\n---- STDERR: --------------\n"; + # print $err; + # print "\n---- STDOUT: --------------\n"; + # print $out; + # print "\n---- EXIT CODE: -----------\n"; + # print $exit / 256; + # print "\n---------------------------\n"; + my $gitea_ssh_status = $err; + if ($gitea_ssh_status =~ /(successful)/gm) { + print "Gitea SSH connection attempt: $1\n"; + } + + + unless ( ($gitea_proc_status =~ /active/) && ($gitea_ssh_status =~ /successfully/gm) ) { + $gitea_status = 0; + } + if ( ($gitea_proc_status =~ /active/) && ($gitea_ssh_status =~ /successfully/gm) ) { + $gitea_status = 1; + } + return $gitea_status, $gitea_proc_status, $gitea_ssh_status; +} + +sub notification { + my ($result, $body, $running_version, $upstream_version) = @_; + my $subject = "Gitea update check: update " . $result; + my $from = 'system@host.tlcnet.info'; + my $ver_body; + + print "[TLC DEBUG] Body received is\n$body\n" if defined $verbose; + + if ( defined $running_version ) { + $ver_body = q{ + + + + + + + + + + + +
Running version:} . $running_version . q{
Upstream version:} . $upstream_version . q{
} + } + + my $msg = MIME::Lite->new( + Subject => encode( 'MIME-Header', $subject ), + From => $from, + To => $email, + Type => 'text/html', + Data => encode_utf8( + ' +

Gitea update result

+

' . $body . '

' . $ver_body . + '
+

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

+

Sincerely,
Your Linode VM

+ ' + ) + ); + + $msg->send(); + + return 1; +}