![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /proc/thread-self/root/opt/cpanel/ea-podman/bin/ |
#!/usr/local/cpanel/3rdparty/bin/perl # cpanel - ea-podman Copyright 2022 cPanel, L.L.C. # All rights Reserved. # [email protected] http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited use strict; use warnings; package scripts::ea_podman; BEGIN { # I cannot get this to work using FindBin in 4 different environments, this works in all # 4 enviroments. # # The environments: # # Testing, in the ea-podman repo dir # Script, in /opt/cpanel/ea-podman/bin/ea-podman # Script, in /usr/local/cpanel/scripts/ea-podman # AdminBin, in /usr/cpanel/local/bin/admin/Cpanel if ( -e '/opt/cpanel/ea-podman/lib' ) { # it has been installed on the machine require '/opt/cpanel/ea-podman/lib/ea_podman/util.pm'; require '/opt/cpanel/ea-podman/lib/ea_podman/subids.pm'; } else { # this is for testing if ( -d 'SOURCES' ) { require './SOURCES/util.pm'; require './SOURCES/subids.pm'; } else { require '/root/git/ea-podman/SOURCES/util.pm'; require '/root/git/ea-podman/SOURCES/subids.pm'; } } } use Cpanel::Config::Users (); use Cpanel::JSON (); use Cpanel::AccessIds (); use Whostmgr::Accounts::Shell (); use Cpanel::Shell (); use Term::ReadLine (); use App::CmdDispatch (); use Try::Tiny; run(@ARGV) unless caller; sub run { my @args = @_; local $Term::ReadLine::termcap_nowarn = 1; my $user = getpwuid($>); my $has_unrestricted_shell; if ( defined &Whostmgr::Accounts::Shell::has_unrestricted_shell ) { $has_unrestricted_shell = Whostmgr::Accounts::Shell::has_unrestricted_shell($user); } else { $has_unrestricted_shell = Cpanel::Shell::has_unrestricted_shell($user); } die "Cannot run ea-podman from a restricted shell\n" if !$has_unrestricted_shell; if ( $ENV{'OPENSSL_NO_DEFAULT_ZLIB'} && $ENV{'OPENSSL_NO_DEFAULT_ZLIB'} == 1 ) { # This is a special case where they are trying to run ea-podman from # inside cPanel Terminal. # # We cannot allow it, they instead should ssh $USER@localhost and # perform the operations. print "You cannot run the /scripts/ea-podman script directly from the cPanel and WHM terminal.\n"; print " To use this script, you must first log in via ssh with the following command:\n"; print " ssh $user\@localhost\n\n"; exit 1; } return App::CmdDispatch->new( get_dispatch_args() )->run(@args); } sub get_dispatch_args { my $hint_blurb = "This tool supports the following commands (i.e. $0 {command} …):"; my %opts = ( 'default_commands' => 'help', # shell is probably not useful here and potentially confusing 'help:pre_hint' => $hint_blurb, 'help:pre_help' => "Various EA4 user-container based service/app/etc management\n\n$hint_blurb", alias => { stat => "status", in => "install", up => "upgrade", un => "uninstall", li => "list", re => "restart", st => "start", sp => "stop", sid => "subids", si => "subids", registered => "containers", running => "list", available => "avail", av => "avail" }, ); if ( $> == 0 ) { $opts{"help:post_help"} = "To manage containers for a user use `su - USER -c '$0 …'` or similar."; $opts{"help:post_hint"} = $opts{"help:post_help"}; } my %cmds = ( subids => { clue => "subids [--ensure]", abstract => "Check and report on sub id config", help => "Checks that use name spaces are enabled or not and if so what sub uids and sub gids are allocated\nOptional --ensure flag, makes sure the subids are setup for this user.", code => sub { my ( $app, @other_args ) = @_; ea_podman::util::init_user(); subids( $app, @other_args ); }, }, install => { clue => "install <PKG> [`run` flags]|install <NON-PKG-NAME> [--cpuser-port=<CONTAINER PORT|0> [--cpuser-port=<ANOTHER CONTAINER PORT|0> …]] [`run` flags] <IMAGE>", abstract => "Install a container", help => "Has two modes:\n\t<PKG> - An EA4 container based package.\n\t\tNeeds no other arguments or setup as that is all provided by the package. It can take some additional start up arguments.\n\t<NON-PKG-NAME> - manage an arbitrary image as if it where an EA4 container based package.\n\t\tSee https://github.com/CpanelInc/ea-podman/blob/master/README.md for details", code => sub { my ( $app, $name, @start_args ) = @_; ea_podman::util::init_user(); my $container_name = ea_podman::util::install_container( $name, @start_args ); print "Done, installed: $container_name\n"; }, }, upgrade => { clue => "upgrade <CONTAINER_NAME>", abstract => "Upgrade a container", help => "Upgrade the container named CONTAINER_NAME", code => sub { my ( $app, $container_name ) = @_; ea_podman::util::init_user(); ea_podman::util::upgrade_container($container_name); }, }, uninstall => { clue => "uninstall <CONTAINER_NAME>", abstract => "Uninstall a container", help => "Uninstall the container named CONTAINER_NAME", code => sub { my ( $app, $container_name, $verify ) = @_; if ( !length($verify) || $verify ne "--verify" ) { print "This operation can not be undone! Please pass `--verify` to verify you really want to do this.\n"; return; } ea_podman::util::init_user(); ea_podman::util::remove_container_by_name($container_name); }, }, list => { clue => "list", abstract => "Show container information", help => "Dumps the information about user’s running containers in human readable JSON", code => sub { my ($app) = @_; ea_podman::util::init_user(); print Cpanel::JSON::pretty_canonical_dump( ea_podman::util::get_containers() ); }, }, start => { clue => "start <CONTAINER_NAME>", abstract => "Start a container", help => "Start the container named CONTAINER_NAME", code => sub { my ( $app, $container_name ) = @_; ea_podman::util::validate_user_container_name($container_name); ea_podman::util::init_user(); my $service_name = ea_podman::util::get_container_service_name($container_name); ea_podman::util::sysctl( start => $service_name ); } }, stop => { clue => "stop <CONTAINER_NAME>", abstract => "Stop a container", help => "Stop the container named CONTAINER_NAME", code => sub { my ( $app, $container_name ) = @_; ea_podman::util::validate_user_container_name($container_name); ea_podman::util::init_user(); my $service_name = ea_podman::util::get_container_service_name($container_name); ea_podman::util::sysctl( stop => $service_name ); } }, restart => { clue => "restart <CONTAINER_NAME>", abstract => "Restart a container", help => "Restart the container named CONTAINER_NAME", code => sub { my ( $app, $container_name ) = @_; ea_podman::util::validate_user_container_name($container_name); ea_podman::util::init_user(); my $service_name = ea_podman::util::get_container_service_name($container_name); ea_podman::util::sysctl( restart => $service_name ); } }, status => { clue => "status <CONTAINER_NAME>", abstract => "Get status of a container", help => "Get status of the container named CONTAINER_NAME", code => sub { my ( $app, $container_name ) = @_; ea_podman::util::validate_user_container_name($container_name); ea_podman::util::init_user(); my $service_name = ea_podman::util::get_container_service_name($container_name); ea_podman::util::sysctl( status => $service_name ); } }, bash => { clue => "bash <CONTAINER_NAME> [CMD]", abstract => "get into a shell/run commands inside the container", help => "If the container has bash: get a shell inside the container or run the (optional) CMD", code => sub { my ( $app, $container_name, $cmd ) = @_; ea_podman::util::validate_user_container_name($container_name); ea_podman::util::init_user(); if ($cmd) { ea_podman::util::podman( exec => "-it", $container_name, "/bin/bash", "-c" => $cmd ); } else { ea_podman::util::podman( exec => "-it", $container_name, "/bin/bash" ); } }, }, containers => { clue => "containers [--all]", abstract => "List containers", help => "List your ea-podman registered containers. root can additionally pass --all to list everyone’s ea-podman registered containers.", code => sub { my ( $app, $all ) = @_; die "Unknown argument “$all”\n" if defined $all && $all ne '--all'; my $user = getpwuid($>); ea_podman::util::init_user(); my $containers_hr = ea_podman::util::load_known_containers(); my %user_containers; foreach my $container ( grep { $_->{user} eq $user } values %{$containers_hr} ) { $user_containers{ $container->{container_name} } = $container; } if ( $> == 0 ) { if ($all) { print Cpanel::JSON::pretty_canonical_dump($containers_hr); } else { print Cpanel::JSON::pretty_canonical_dump( \%user_containers ); } } else { if ($all) { die "Only root can specifically --all\n"; } else { print Cpanel::JSON::pretty_canonical_dump( \%user_containers ); } } }, }, remove_containers => { clue => "remove_containers [<PKG|NON-PKG-NAME>|--all]", abstract => "Remove containers", help => qq{Remove ea-podman registered containers by EA4 package, an arbitrary non-package name, or all via `--all`. - as non-root will only affect only the user - as root this will effect all users This is intended to make it easier for a user to purge their ea-podman based containers and to facilitate cleanup when uninstalling packages that the containers need to run. }, code => sub { my ( $app, $pkg ) = @_; die "Please provide a package name or the flag `--all`\n" if ( !$pkg ); ea_podman::util::init_user(); # TODO ZC-9746: have them verify they want to do this destructive thing my $user = getpwuid($>); my $containers_hr = ea_podman::util::load_known_containers(); my @containers = values %{$containers_hr}; @containers = grep { $_->{user} eq $user } @containers if ( $user ne "root" ); if ( $pkg ne '--all' ) { @containers = grep { ( defined $_->{pkg} && $_->{pkg} eq $pkg ) # <PKG> form … || # … OR … ( !defined $_->{pkg} && $_->{container_name} =~ m/^\Q$pkg\E\.$user\.[0-9][0-9]$/ ) # … <NON-PKG-NAME> form } @containers; } @containers = sort { $a->{user} cmp $b->{user} } @containers; if ( @containers == 0 ) { print "There are no containers\n"; exit 0; } if ( $user eq "root" ) { my %user_breakdown; foreach my $container (@containers) { my $c_user = $container->{user}; push( @{ $user_breakdown{$c_user} }, $container ); } foreach my $c_user ( keys %user_breakdown ) { if ( $c_user eq "root" ) { ea_podman::util::remove_containers_for_a_user( @{ $user_breakdown{$c_user} } ); } else { try { Cpanel::AccessIds::do_as_user_with_exception( $c_user, sub { my $homedir = ( getpwuid($>) )[7]; local $ENV{HOME} = $homedir; local $ENV{USER} = $c_user; chdir($homedir); ea_podman::util::init_user(); ea_podman::util::remove_containers_for_a_user( @{ $user_breakdown{$c_user} } ); } ); } catch { my $err = $_; # Handles cases where users are not removed cleanly (with the use of a cPanel script/API), therefore it tries to manage containers as the deleted user # which causes unistall of containerized packages to fail (see ZC-10958) if ( $err->isa("Cpanel::Exception::UserNotFound") ) { ea_podman::util::remove_containers_for_a_deleted_user( @{ $user_breakdown{$c_user} } ); return; } # Rethrow any other exception type die $err; }; } } } else { ea_podman::util::init_user(); ea_podman::util::remove_containers_for_a_user(@containers); } }, }, upgrade_containers => { clue => "upgrade_containers [<PKG|NON-PKG-NAME>|--all]", abstract => "Upgrade containers", help => qq{Upgrade ea-podman registered containers by EA4 package, an arbitrary non-package name, or all via `--all`. - as non-root will only affect only the user - as root this will effect all users }, code => sub { my ( $app, $pkg ) = @_; die "Please provide a package name or the flag `--all`\n" if ( !$pkg ); my $user = getpwuid($>); my $containers_hr = ea_podman::util::load_known_containers(); my @containers = values %{$containers_hr}; @containers = grep { $_->{user} eq $user } @containers if ( $user ne "root" ); if ( $pkg ne '--all' ) { @containers = grep { ( defined $_->{pkg} && $_->{pkg} eq $pkg ) # <PKG> form … || # … OR … ( !defined $_->{pkg} && $_->{container_name} =~ m/^\Q$pkg\E\.$user\.[0-9][0-9]$/ ) # … <NON-PKG-NAME> form } @containers; } @containers = sort { $a->{user} cmp $b->{user} } @containers; if ( @containers == 0 ) { print "There are no containers\n"; exit 0; } if ( $user eq "root" ) { my %user_breakdown; foreach my $container (@containers) { my $c_user = $container->{user}; push( @{ $user_breakdown{$c_user} }, $container ); } foreach my $c_user ( keys %user_breakdown ) { if ( $c_user eq "root" ) { ea_podman::util::upgrade_containers_for_a_user( @{ $user_breakdown{$c_user} } ); } else { Cpanel::AccessIds::do_as_user_with_exception( $c_user, sub { my $homedir = ( getpwuid($>) )[7]; local $ENV{HOME} = $homedir; local $ENV{USER} = $c_user; chdir($homedir); ea_podman::util::init_user(); ea_podman::util::upgrade_containers_for_a_user( @{ $user_breakdown{$c_user} } ); } ); } } } else { ea_podman::util::init_user(); ea_podman::util::upgrade_containers_for_a_user(@containers); } }, }, backup => { clue => "backup", abstract => "Backup containers", help => qq{Backup all ea-podman registered containers for a user. Outputs a file ea_podman_backup_<USER>.json }, code => sub { my ($app) = @_; die "Backup is not allowed for the root user at this time.\n" if ( $> == 0 ); ea_podman::util::perform_user_backup(); }, }, restore => { clue => "restore <BACKUP_FILE_PATH> [--verify]", abstract => "Restore containers that have been backed up.", help => qq{Will restore containers that bave been backed up. NOTE: * Will remove existing containers * Will destroy the ea-podman.d directory * This is a destructive operation, you are required to pass ”--verify” }, code => sub { my ( $app, $backup_file, $verify ) = @_; die "Restore is not allowed for the root user at this time.\n" if ( $> == 0 ); die "Please pass in the path to the backup file you want to restore.\n" if ( !$backup_file ); die "Backup file cannot be read\n" if ( !-r $backup_file ); if ( !length($verify) || $verify ne "--verify" ) { print "This operation can not be undone! Please pass `--verify` to verify you really want to do this.\n"; return; } ea_podman::util::perform_user_restore($backup_file); }, }, avail => { clue => "avail", abstract => "list available EA4 container based packages", help => "lists available EA4 container based packages and, for each one, shows if its installed locally or not and has a URL to its documentation", code => sub { my ($app) = @_; my $e4m = Cpanel::JSON::LoadFile("/etc/cpanel/ea4/ea4-metainfo.json"); if ( !exists $e4m->{container_based_packages} ) { die "Container based packages list not found (need to upgrade ea-cpanel-tools?)\n"; } my %avail; for my $pkg ( @{ $e4m->{container_based_packages} } ) { $avail{$pkg}{installed_locally} = -e "/opt/cpanel/$pkg/pkg-version" ? 1 : 0; $avail{$pkg}{url} = "https://github.com/CpanelInc/$pkg/blob/master/SOURCES/README.md"; } print Cpanel::JSON::pretty_canonical_dump( \%avail ); return 1; }, }, rootbackupofuser => { clue => "rootbackupofuser - internal use only", abstract => "internal use only", help => "internal use only", code => sub { my ( $app, $user ) = @_; require Cpanel::AccessIds; Cpanel::AccessIds::do_as_user_with_exception( $user, sub { my $homedir = ( getpwuid($<) )[7]; local $ENV{HOME} = $homedir; local $ENV{USER} = $user; chdir($homedir); ea_podman::util::init_user(); ea_podman::util::perform_user_backup(); } ); return 1; }, }, ); return ( \%cmds, \%opts ); } #################### #### sub commands ## #################### sub subids { my ( $app, @other ) = @_; ea_podman::subids::assert_has_user_namespaces(1); if ( @other == 1 && $other[0] eq "--ensure" ) { ea_podman::util::ensure_user(); # do not need init_user because we don’t care aboue the su login stuff here } else { die "Too many arguments" if @other > 1; die "--ensure is the only allowed argument" if @other && $other[0] ne "--ensure"; } my $subuid_lu = ea_podman::subids::get_subuids(); my $subgid_lu = ea_podman::subids::get_subgids(); if ( $> == 0 ) { for my $user ( "root", Cpanel::Config::Users::getcpusers() ) { _check_output_user( $user, $subuid_lu, $subgid_lu ); } } else { my $user = getpwuid($>); _check_output_user( $user, $subuid_lu, $subgid_lu ); } } sub _check_output_user { my ( $user, $subuid_lu, $subgid_lu ) = @_; print( exists $subuid_lu->{$user} ? "$ea_podman::subids::good “$user” has subuids ($subuid_lu->{$user})\n" : "$ea_podman::subids::bad “$user” does not have subuids\n" ); print( exists $subgid_lu->{$user} ? "$ea_podman::subids::good “$user” has subgids ($subgid_lu->{$user})\n" : "$ea_podman::subids::bad “$user” does not have subgids\n" ); } 1;