From 84b2f464c9e844612c59b692d0d7bb83bdc58d02 Mon Sep 17 00:00:00 2001 From: shuki Date: Wed, 4 Mar 2026 03:41:40 +0200 Subject: [PATCH] Add remote directory init on WHM remote creation When adding a remote via WHM, create the base directory structure on the remote server (matching gniza init remote CLI behavior). Creates $REMOTE_BASE//accounts/ via SSH mkdir or rclone mkdir. Co-Authored-By: Claude Opus 4.6 --- whm/gniza-whm/lib/GnizaWHM/UI.pm | 62 ++++++++++++++++++++++++++++++++ whm/gniza-whm/remotes.cgi | 25 +++++++++++++ 2 files changed, 87 insertions(+) diff --git a/whm/gniza-whm/lib/GnizaWHM/UI.pm b/whm/gniza-whm/lib/GnizaWHM/UI.pm index cbab9ed..ea4ff16 100644 --- a/whm/gniza-whm/lib/GnizaWHM/UI.pm +++ b/whm/gniza-whm/lib/GnizaWHM/UI.pm @@ -463,6 +463,68 @@ sub test_rclone_connection { return (0, $msg); } +# ── Remote Init (create base directory) ────────────────────── + +sub init_remote_dir { + my (%args) = @_; + my $type = $args{type} // 'ssh'; + my $base = $args{remote_base} // '/backups'; + + chomp(my $hostname = `hostname -f 2>/dev/null` || `hostname`); + my $remote_path = "$base/$hostname/accounts"; + + if ($type eq 'ssh') { + my @ssh_args = ( + 'ssh', '-n', + '-p', ($args{port} || '22'), + '-o', 'StrictHostKeyChecking=accept-new', + '-o', 'ConnectTimeout=10', + '-o', 'BatchMode=yes', + ); + + if (($args{auth_method} // 'key') eq 'password') { + push @ssh_args, "$args{user}\@$args{host}", "mkdir -p '$remote_path'"; + my @cmd = ('sshpass', '-p', $args{password}, @ssh_args); + system(@cmd); + } else { + push @ssh_args, '-i', $args{key}; + push @ssh_args, "$args{user}\@$args{host}", "mkdir -p '$remote_path'"; + system(@ssh_args); + } + return ($? == 0, $? == 0 ? undef : "Failed to create remote directory"); + } + elsif ($type eq 's3' || $type eq 'gdrive') { + my $tmpfile = "/tmp/gniza-rclone-init-$$.conf"; + my $conf_content = ''; + my $rclone_path = ''; + + if ($type eq 's3') { + $conf_content = "[remote]\ntype = s3\nprovider = AWS\naccess_key_id = $args{s3_access_key_id}\nsecret_access_key = $args{s3_secret_access_key}\nregion = " . ($args{s3_region} || 'us-east-1') . "\n"; + $conf_content .= "endpoint = $args{s3_endpoint}\n" if ($args{s3_endpoint} // '') ne ''; + $rclone_path = "remote:$args{s3_bucket}$remote_path"; + } else { + $conf_content = "[remote]\ntype = drive\nscope = drive\nservice_account_file = $args{gdrive_service_account_file}\n"; + $conf_content .= "root_folder_id = $args{gdrive_root_folder_id}\n" if ($args{gdrive_root_folder_id} // '') ne ''; + $rclone_path = "remote:$remote_path"; + } + + if (open my $fh, '>', $tmpfile) { + print $fh $conf_content; + close $fh; + chmod 0600, $tmpfile; + } else { + return (0, "Failed to write temp rclone config: $!"); + } + + system('rclone', '--config', $tmpfile, 'mkdir', $rclone_path); + my $ok = ($? == 0); + unlink $tmpfile; + return ($ok, $ok ? undef : "Failed to create remote directory"); + } + + return (0, "Unknown remote type: $type"); +} + # ── Page Wrappers ──────────────────────────────────────────── sub page_header { diff --git a/whm/gniza-whm/remotes.cgi b/whm/gniza-whm/remotes.cgi index ab1b936..84608e6 100644 --- a/whm/gniza-whm/remotes.cgi +++ b/whm/gniza-whm/remotes.cgi @@ -267,6 +267,31 @@ sub handle_add { } my ($ok, $err) = GnizaWHM::Config::write($dest, \%data, \@GnizaWHM::Config::REMOTE_KEYS); if ($ok) { + # Init remote directory structure (like gniza init remote) + my $type = $data{REMOTE_TYPE} || 'ssh'; + my %init_args = ( + type => $type, + remote_base => $data{REMOTE_BASE} || '/backups', + ); + if ($type eq 'ssh') { + $init_args{host} = $data{REMOTE_HOST}; + $init_args{port} = $data{REMOTE_PORT} || '22'; + $init_args{user} = $data{REMOTE_USER} || 'root'; + $init_args{auth_method} = $data{REMOTE_AUTH_METHOD} || 'key'; + $init_args{key} = $data{REMOTE_KEY}; + $init_args{password} = $data{REMOTE_PASSWORD}; + } elsif ($type eq 's3') { + $init_args{s3_access_key_id} = $data{S3_ACCESS_KEY_ID}; + $init_args{s3_secret_access_key} = $data{S3_SECRET_ACCESS_KEY}; + $init_args{s3_region} = $data{S3_REGION}; + $init_args{s3_endpoint} = $data{S3_ENDPOINT}; + $init_args{s3_bucket} = $data{S3_BUCKET}; + } else { + $init_args{gdrive_service_account_file} = $data{GDRIVE_SERVICE_ACCOUNT_FILE}; + $init_args{gdrive_root_folder_id} = $data{GDRIVE_ROOT_FOLDER_ID}; + } + GnizaWHM::UI::init_remote_dir(%init_args); + if ($form->{'wizard'}) { GnizaWHM::UI::set_flash('success', "Remote '$name' created. Now set up a schedule."); print "Status: 302 Found\r\n";