jina verze
This commit is contained in:
@@ -9,7 +9,7 @@ defined $mode && length $mode or die "mode is required\n";
|
||||
|
||||
sub mask_to_re {
|
||||
my ($mask) = @_;
|
||||
return if !defined($mask) || $mask eq '';
|
||||
return undef if !defined($mask) || $mask eq '';
|
||||
$mask = quotemeta($mask);
|
||||
$mask =~ s/\\\*/.*/g;
|
||||
return qr/\A$mask\z/;
|
||||
@@ -43,70 +43,34 @@ sub fmt_line {
|
||||
|
||||
sub brace_delta {
|
||||
my ($line) = @_;
|
||||
return ($line =~ tr/\{//) - ($line =~ tr/\}//);
|
||||
my $o = () = $line =~ /\{/g;
|
||||
my $c = () = $line =~ /\}/g;
|
||||
return $o - $c;
|
||||
}
|
||||
|
||||
sub key_add {
|
||||
my ($lines, $section_re, $key, $value) = @_;
|
||||
# die "value is required for add\n" if !defined($value) || $value eq '';
|
||||
sub find_section {
|
||||
my ($lines, $re) = @_;
|
||||
|
||||
if ($section_re eq '') {
|
||||
my $depth = 0;
|
||||
for (my $i = 0; $i <= $#$lines; $i++) {
|
||||
next unless $lines->[$i] =~ /^(\h*)$re\h*\{\h*(?:\R)?$/;
|
||||
|
||||
for my $line (@$lines) {
|
||||
if ($depth == 0 && line_matches_exact($line, $key, $value)) {
|
||||
return;
|
||||
}
|
||||
$depth += brace_delta($line);
|
||||
}
|
||||
|
||||
my $new = fmt_line('', $key, $value);
|
||||
|
||||
my $root_pos;
|
||||
my $first_block_pos;
|
||||
$depth = 0;
|
||||
|
||||
for (my $i = 0; $i <= $#$lines; $i++) {
|
||||
my $line = $lines->[$i];
|
||||
my $indent = $1 . ' ';
|
||||
my $depth = 1;
|
||||
|
||||
for (my $j = $i + 1; $j <= $#$lines; $j++) {
|
||||
$depth += brace_delta($lines->[$j]);
|
||||
if ($depth == 0) {
|
||||
$root_pos = $i
|
||||
if !defined($root_pos) && $line =~ /^\h*serverName\h+\S*/;
|
||||
|
||||
$first_block_pos = $i
|
||||
if !defined($first_block_pos) && $line =~ /^\h*\S.*\{\h*(?:\R)?$/;
|
||||
return ($i, $j, $indent);
|
||||
}
|
||||
|
||||
$depth += brace_delta($line);
|
||||
}
|
||||
|
||||
if (defined $root_pos) {
|
||||
splice @$lines, $root_pos + 1, 0, $new;
|
||||
} elsif (defined $first_block_pos) {
|
||||
splice @$lines, $first_block_pos, 0, $new;
|
||||
} else {
|
||||
push @$lines, $new;
|
||||
}
|
||||
|
||||
return;
|
||||
die "section '$re' is not closed\n";
|
||||
}
|
||||
|
||||
my ($start, $end, $indent) = block_find($lines, $section_re);
|
||||
|
||||
my $depth = 1;
|
||||
for my $i ($start + 1 .. $end - 1) {
|
||||
my $line = $lines->[$i];
|
||||
if ($depth == 1 && line_matches_exact($line, $key, $value)) {
|
||||
return;
|
||||
}
|
||||
$depth += brace_delta($line);
|
||||
}
|
||||
|
||||
my $new = fmt_line($indent, $key, $value);
|
||||
splice @$lines, $end, 0, $new;
|
||||
die "section '$re' not found\n";
|
||||
}
|
||||
|
||||
sub key_del {
|
||||
sub delete_key {
|
||||
my ($lines, $section_re, $key, $mask) = @_;
|
||||
my $value_re = mask_to_re($mask);
|
||||
|
||||
@@ -124,7 +88,7 @@ sub key_del {
|
||||
return;
|
||||
}
|
||||
|
||||
my ($start, $end, undef) = block_find($lines, $section_re);
|
||||
my ($start, $end, undef) = find_section($lines, $section_re);
|
||||
|
||||
my @out;
|
||||
push @out, @$lines[0 .. $start];
|
||||
@@ -141,45 +105,111 @@ sub key_del {
|
||||
@$lines = @out;
|
||||
}
|
||||
|
||||
sub block_find {
|
||||
my ($lines, $re) = @_;
|
||||
sub add_key {
|
||||
my ($lines, $section_re, $key, $value) = @_;
|
||||
die "value is required for add\n" if !defined($value) || $value eq '';
|
||||
|
||||
for (my $i = 0; $i <= $#$lines; $i++) {
|
||||
next unless $lines->[$i] =~ /^(\h*)$re\h*\{\h*(?:\R)?$/;
|
||||
if ($section_re eq '') {
|
||||
my $depth = 0;
|
||||
|
||||
my $indent = $1 . ' ';
|
||||
my $depth = 1;
|
||||
|
||||
for (my $j = $i + 1; $j <= $#$lines; $j++) {
|
||||
$depth += brace_delta($lines->[$j]);
|
||||
if ($depth == 0) {
|
||||
return ($i, $j, $indent);
|
||||
for my $line (@$lines) {
|
||||
if ($depth == 0 && line_matches_exact($line, $key, $value)) {
|
||||
return;
|
||||
}
|
||||
$depth += brace_delta($line);
|
||||
}
|
||||
|
||||
die "block '$re' is not closed\n";
|
||||
my $new = fmt_line('', $key, $value);
|
||||
|
||||
my $root_pos;
|
||||
my $first_section_pos;
|
||||
$depth = 0;
|
||||
|
||||
for (my $i = 0; $i <= $#$lines; $i++) {
|
||||
my $line = $lines->[$i];
|
||||
|
||||
if ($depth == 0) {
|
||||
$root_pos = $i
|
||||
if !defined($root_pos) && $line =~ /^\h*serverName\h+\S*/;
|
||||
|
||||
$first_section_pos = $i
|
||||
if !defined($first_section_pos) && $line =~ /^\h*\S.*\{\h*(?:\R)?$/;
|
||||
}
|
||||
|
||||
$depth += brace_delta($line);
|
||||
}
|
||||
|
||||
if (defined $root_pos) {
|
||||
splice @$lines, $root_pos + 1, 0, $new;
|
||||
} elsif (defined $first_section_pos) {
|
||||
splice @$lines, $first_section_pos, 0, $new;
|
||||
} else {
|
||||
push @$lines, $new;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
die "block '$re' not found\n";
|
||||
my ($start, $end, $indent) = find_section($lines, $section_re);
|
||||
|
||||
my $depth = 1;
|
||||
for my $i ($start + 1 .. $end - 1) {
|
||||
my $line = $lines->[$i];
|
||||
if ($depth == 1 && line_matches_exact($line, $key, $value)) {
|
||||
return;
|
||||
}
|
||||
$depth += brace_delta($line);
|
||||
}
|
||||
|
||||
my $new = fmt_line($indent, $key, $value);
|
||||
splice @$lines, $end, 0, $new;
|
||||
}
|
||||
|
||||
sub block_add {
|
||||
my ($lines, $header) = @_;
|
||||
return if !defined($header) || $header eq '';
|
||||
sub build_vhost_section {
|
||||
my ($domain) = @_;
|
||||
return if !defined($domain) || $domain eq '';
|
||||
|
||||
my @out;
|
||||
push @out, "virtualhost $domain {\n";
|
||||
push @out, fmt_line(' ', 'vhRoot', "/var/www/vhosts/$domain");
|
||||
push @out, fmt_line(' ', 'configFile', "/usr/local/lsws/conf/vhosts/$domain.conf");
|
||||
push @out, fmt_line(' ', 'allowSymbolLink', '1');
|
||||
push @out, fmt_line(' ', 'enableScript', '1');
|
||||
push @out, fmt_line(' ', 'restrained', '1');
|
||||
push @out, fmt_line(' ', 'setUIDMode', '2');
|
||||
push @out, "}\n";
|
||||
|
||||
return join('', @out);
|
||||
}
|
||||
|
||||
sub has_vhost_section {
|
||||
my ($lines, $name) = @_;
|
||||
|
||||
for my $line (@$lines) {
|
||||
return if $line =~ /^\h*\Q$header\E\h*\{/;
|
||||
return 1 if $line =~ /^\h*virtualhost\h+\Q$name\E\h*\{/;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub add_vhost_section {
|
||||
my ($lines, $name) = @_;
|
||||
|
||||
return if !defined($name) || $name eq '';
|
||||
return if has_vhost_section($lines, $name);
|
||||
|
||||
my @section = split /(?<=\n)/, build_vhost_section($name), -1;
|
||||
pop @section if @section && $section[-1] eq '';
|
||||
|
||||
if (@$lines && $lines->[-1] !~ /\n\z/) {
|
||||
$lines->[-1] .= "\n";
|
||||
}
|
||||
|
||||
push @$lines, "\n" if @$lines && $lines->[-1] !~ /^\s*$/;
|
||||
push @$lines, "$header {\n";
|
||||
push @$lines, "}\n";
|
||||
push @$lines, @section;
|
||||
}
|
||||
|
||||
sub block_del {
|
||||
sub delete_named_section {
|
||||
my ($lines, $header_re) = @_;
|
||||
|
||||
my @out;
|
||||
@@ -207,19 +237,7 @@ sub block_del {
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
sub suspended_rebuild {
|
||||
my ($lines, @list) = @_;
|
||||
|
||||
@list = grep { defined($_) && $_ ne '' } @list;
|
||||
|
||||
key_del($lines, '', 'suspendedVhosts', '');
|
||||
|
||||
if (@list) {
|
||||
key_add($lines, '', 'suspendedVhosts', join(',', @list));
|
||||
}
|
||||
}
|
||||
|
||||
sub suspended_list {
|
||||
sub get_suspended_vhosts {
|
||||
my ($lines) = @_;
|
||||
|
||||
my $depth = 0;
|
||||
@@ -238,20 +256,61 @@ sub suspended_list {
|
||||
return;
|
||||
}
|
||||
|
||||
sub suspended_add {
|
||||
my ($lines, $domain) = @_;
|
||||
return if !defined($domain) || $domain eq '';
|
||||
sub set_suspended_vhosts {
|
||||
my ($lines, @list) = @_;
|
||||
|
||||
my @current = suspended_list($lines);
|
||||
return if grep { $_ eq $domain } @current;
|
||||
suspended_rebuild($lines, @current, $domain);
|
||||
@list = grep { defined($_) && $_ ne '' } @list;
|
||||
|
||||
delete_key($lines, '', 'suspendedVhosts', '');
|
||||
|
||||
if (@list) {
|
||||
add_key($lines, '', 'suspendedVhosts', join(',', @list));
|
||||
}
|
||||
}
|
||||
|
||||
sub suspended_del {
|
||||
sub suspend_vhost {
|
||||
my ($lines, $domain) = @_;
|
||||
return if !defined($domain) || $domain eq '';
|
||||
|
||||
suspended_rebuild($lines, grep { $_ ne $domain } suspended_list($lines));
|
||||
my @current = get_suspended_vhosts($lines);
|
||||
|
||||
my @new = ($domain);
|
||||
for my $item (@current) {
|
||||
push @new, $item if $item ne $domain;
|
||||
}
|
||||
|
||||
set_suspended_vhosts($lines, @new);
|
||||
}
|
||||
|
||||
sub unsuspend_vhost {
|
||||
my ($lines, $domain) = @_;
|
||||
return if !defined($domain) || $domain eq '';
|
||||
|
||||
my @current = get_suspended_vhosts($lines);
|
||||
my @new = grep { $_ ne $domain } @current;
|
||||
|
||||
set_suspended_vhosts($lines, @new);
|
||||
}
|
||||
|
||||
sub get_listener_http_maps {
|
||||
my ($lines) = @_;
|
||||
|
||||
my ($start, $end, undef) = find_section($lines, 'listener\h+HTTP');
|
||||
|
||||
my @maps;
|
||||
|
||||
for my $i ($start + 1 .. $end - 1) {
|
||||
my $clean = $lines->[$i];
|
||||
$clean =~ s/#.*$//;
|
||||
$clean =~ s/^\s+|\s+$//g;
|
||||
next if $clean eq '';
|
||||
|
||||
if ($clean =~ /^map\s+(\S+)\s+(\S+)$/i) {
|
||||
push @maps, [$1, $2];
|
||||
}
|
||||
}
|
||||
|
||||
return @maps;
|
||||
}
|
||||
|
||||
sub vhost_list {
|
||||
@@ -262,7 +321,7 @@ sub vhost_list {
|
||||
if $type !~ /\A(?:all|up|down)\z/;
|
||||
|
||||
my @all;
|
||||
my %down = map { $_ => 1 } suspended_list($lines);
|
||||
my %down = map { $_ => 1 } get_suspended_vhosts($lines);
|
||||
|
||||
for my $line (@$lines) {
|
||||
my $clean = $line;
|
||||
@@ -284,30 +343,44 @@ sub vhost_list {
|
||||
}
|
||||
}
|
||||
|
||||
sub vhost_del {
|
||||
my ($lines, $domain) = @_;
|
||||
sub vhost_list_map {
|
||||
my ($lines, $type) = @_;
|
||||
$type //= 'all';
|
||||
|
||||
key_del($lines, 'listener\h+HTTP', 'map', "$domain *");
|
||||
block_del($lines, 'virtualhost\h+' . quotemeta($domain));
|
||||
die "unknown vhost map list type '$type'\n"
|
||||
if $type !~ /\A(?:all|up|down)\z/;
|
||||
|
||||
my %down = map { $_ => 1 } get_suspended_vhosts($lines);
|
||||
my %seen;
|
||||
|
||||
for my $map (get_listener_http_maps($lines)) {
|
||||
my ($vhost, $domain) = @$map;
|
||||
|
||||
next if $vhost ne $domain;
|
||||
next if $seen{$vhost}++;
|
||||
|
||||
if ($type eq 'down') {
|
||||
next if !exists $down{$vhost};
|
||||
} elsif ($type eq 'up') {
|
||||
next if exists $down{$vhost};
|
||||
}
|
||||
|
||||
print "$vhost\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub vhost_set {
|
||||
my ($lines, $vhRoot, $domain, @aliases) = @_;
|
||||
sub alias_list {
|
||||
my ($lines) = @_;
|
||||
|
||||
vhost_del($lines, $domain);
|
||||
block_add($lines, "virtualhost $domain");
|
||||
my %seen;
|
||||
|
||||
my $block_re = 'virtualhost\h+' . quotemeta($domain);
|
||||
key_add($lines, $block_re, 'vhRoot', $vhRoot);
|
||||
key_add($lines, $block_re, 'configFile', "/usr/local/lsws/conf/vhosts/$domain.conf");
|
||||
key_add($lines, $block_re, 'allowSymbolLink', '1');
|
||||
key_add($lines, $block_re, 'enableScript', '1');
|
||||
key_add($lines, $block_re, 'restrained', '1');
|
||||
key_add($lines, $block_re, 'setUIDMode', '2');
|
||||
for my $map (get_listener_http_maps($lines)) {
|
||||
my ($vhost, $domain) = @$map;
|
||||
|
||||
key_add($lines, 'listener\h+HTTP', 'map', "$domain $domain");
|
||||
for my $alias (@aliases) {
|
||||
key_add($lines, 'listener\h+HTTP', 'map', "$domain $alias");
|
||||
next if $vhost eq $domain;
|
||||
next if $seen{$domain}++;
|
||||
|
||||
print "$domain\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,140 +390,19 @@ sub vhost_alias {
|
||||
die "virtual host name is required\n"
|
||||
if !defined($name) || $name eq '';
|
||||
|
||||
my ($start, $end) = block_find($lines, 'listener\h+HTTP');
|
||||
|
||||
my %seen;
|
||||
|
||||
for my $i ($start + 1 .. $end - 1) {
|
||||
my $clean = $lines->[$i];
|
||||
$clean =~ s/#.*$//;
|
||||
$clean =~ s/^\s+|\s+$//g;
|
||||
next if $clean eq '';
|
||||
next unless $clean =~ /^map\s+(\S+)\s+(\S+)$/i;
|
||||
for my $map (get_listener_http_maps($lines)) {
|
||||
my ($vhost, $domain) = @$map;
|
||||
|
||||
my ($vhost, $domain) = ($1, $2);
|
||||
|
||||
next if $name ne 'all' && $vhost ne $name;
|
||||
next if $domain eq $vhost;
|
||||
next if $vhost ne $name;
|
||||
next if $domain eq $name;
|
||||
next if $seen{$domain}++;
|
||||
|
||||
print "$domain\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub member_list {
|
||||
my ($lines, $template, $type) = @_;
|
||||
|
||||
my ($t_start, $t_end) = block_find($lines, 'vhTemplate\h+' . quotemeta($template));
|
||||
|
||||
die "unknown member list type '$type'\n"
|
||||
if $type !~ /\A(?:all|up|down)\z/;
|
||||
|
||||
my %down = map { $_ => 1 } suspended_list($lines);
|
||||
|
||||
my $depth = 0;
|
||||
for my $i ($t_start + 1 .. $t_end - 1) {
|
||||
my $line = $lines->[$i];
|
||||
|
||||
if ($depth == 0 && $line =~ /^\h*member\h+([^\s\{]+)/i) {
|
||||
my $name = $1;
|
||||
if ( $type eq 'all'
|
||||
|| ($type eq 'down' && exists $down{$name})
|
||||
|| ($type eq 'up' && !exists $down{$name})) {
|
||||
print "$name\n";
|
||||
}
|
||||
}
|
||||
|
||||
$depth += brace_delta($line);
|
||||
}
|
||||
}
|
||||
|
||||
sub member_del {
|
||||
my ($lines, $template, $domain) = @_;
|
||||
|
||||
my ($t_start, $t_end) = block_find($lines, 'vhTemplate\h+' . quotemeta($template));
|
||||
|
||||
my $depth = 0;
|
||||
for my $i ($t_start + 1 .. $t_end - 1) {
|
||||
my $line = $lines->[$i];
|
||||
|
||||
if ($depth == 0 && $line =~ /^\h*member\h+\Q$domain\E\h*(\{)?\h*(?:\R)?$/) {
|
||||
my $m_end = $i;
|
||||
|
||||
if (defined $1) {
|
||||
my $d = 1;
|
||||
for my $j ($i + 1 .. $t_end - 1) {
|
||||
$d += brace_delta($lines->[$j]);
|
||||
if ($d == 0) { $m_end = $j; last; }
|
||||
}
|
||||
die "member '$domain' block is not closed\n" if $m_end == $i;
|
||||
}
|
||||
|
||||
splice @$lines, $i, $m_end - $i + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
$depth += brace_delta($line);
|
||||
}
|
||||
}
|
||||
|
||||
sub member_set {
|
||||
my ($lines, $template, $domain, @aliases) = @_;
|
||||
|
||||
member_del($lines, $template, $domain);
|
||||
|
||||
my ($t_start, $t_end, $indent) = block_find($lines, 'vhTemplate\h+' . quotemeta($template));
|
||||
|
||||
my @new;
|
||||
if (@aliases) {
|
||||
push @new, fmt_line($indent, 'member', "$domain {");
|
||||
push @new, fmt_line($indent . ' ', 'vhAliases', join(', ', @aliases));
|
||||
push @new, "$indent}\n";
|
||||
} else {
|
||||
push @new, fmt_line($indent, 'member', $domain);
|
||||
}
|
||||
|
||||
splice @$lines, $t_end, 0, @new;
|
||||
}
|
||||
|
||||
sub member_alias {
|
||||
my ($lines, $template, $domain) = @_;
|
||||
|
||||
my ($t_start, $t_end) = block_find($lines, 'vhTemplate\h+' . quotemeta($template));
|
||||
|
||||
my $depth = 0;
|
||||
for my $i ($t_start + 1 .. $t_end - 1) {
|
||||
my $line = $lines->[$i];
|
||||
|
||||
if ($depth == 0 && $line =~ /^\h*member\h+(\S+)\h*\{\h*(?:\R)?$/) {
|
||||
my $mname = $1;
|
||||
my $match = ($domain eq 'all' || $domain eq $mname);
|
||||
|
||||
if ($match) {
|
||||
my $d = 1;
|
||||
for my $j ($i + 1 .. $t_end - 1) {
|
||||
if ($d == 1) {
|
||||
my @m = parse_kv_line($lines->[$j], 'vhAliases');
|
||||
if (@m) {
|
||||
for my $a (split /\h*,\h*/, $m[1]) {
|
||||
next if $a eq '';
|
||||
print "$a\n";
|
||||
}
|
||||
last;
|
||||
}
|
||||
}
|
||||
$d += brace_delta($lines->[$j]);
|
||||
last if $d == 0;
|
||||
}
|
||||
|
||||
return unless $domain eq 'all';
|
||||
}
|
||||
}
|
||||
|
||||
$depth += brace_delta($line);
|
||||
}
|
||||
}
|
||||
|
||||
open my $fh, '<', $file or die "cannot read '$file': $!\n";
|
||||
local $/;
|
||||
my $content = <$fh>;
|
||||
@@ -458,121 +410,89 @@ close $fh;
|
||||
|
||||
my @L = split /(?<=\n)/, $content, -1;
|
||||
|
||||
if ($mode eq 'key_add') {
|
||||
my ($block_re, $key, $value) = @args;
|
||||
defined $block_re or die "block_re is required\n";
|
||||
defined $key or die "key is required\n";
|
||||
defined $value or die "value is required\n";
|
||||
key_add(\@L, $block_re, $key, $value);
|
||||
}
|
||||
elsif ($mode eq 'key_set') {
|
||||
my ($block_re, $key, $value) = @args;
|
||||
defined $block_re or die "block_re is required\n";
|
||||
defined $key or die "key is required\n";
|
||||
defined $value or die "value is required\n";
|
||||
key_del(\@L, $block_re, $key, '');
|
||||
key_add(\@L, $block_re, $key, $value);
|
||||
}
|
||||
elsif ($mode eq 'key_mask_set') {
|
||||
my ($block_re, $key, $mask, $value) = @args;
|
||||
defined $block_re or die "block_re is required\n";
|
||||
defined $key or die "key is required\n";
|
||||
defined $mask or die "mask is required\n";
|
||||
defined $value or die "value is required\n";
|
||||
key_del(\@L, $block_re, $key, $mask);
|
||||
key_add(\@L, $block_re, $key, $value);
|
||||
}
|
||||
elsif ($mode eq 'key_del') {
|
||||
my ($block_re, $key, $mask) = @args;
|
||||
defined $block_re or die "block_re is required\n";
|
||||
if ($mode eq 'del') {
|
||||
my ($section_re, $key, $mask) = @args;
|
||||
defined $section_re or die "section_re is required\n";
|
||||
defined $key or die "key is required\n";
|
||||
$mask //= '';
|
||||
key_del(\@L, $block_re, $key, $mask);
|
||||
delete_key(\@L, $section_re, $key, $mask);
|
||||
}
|
||||
elsif ($mode eq 'key_mask_del') {
|
||||
my ($block_re, $key, $mask) = @args;
|
||||
defined $block_re or die "block_re is required\n";
|
||||
elsif ($mode eq 'add') {
|
||||
my ($section_re, $key, $value) = @args;
|
||||
defined $section_re or die "section_re is required\n";
|
||||
defined $key or die "key is required\n";
|
||||
defined $value or die "value is required\n";
|
||||
add_key(\@L, $section_re, $key, $value);
|
||||
}
|
||||
elsif ($mode eq 'set') {
|
||||
my ($section_re, $key, $value) = @args;
|
||||
defined $section_re or die "section_re is required\n";
|
||||
defined $key or die "key is required\n";
|
||||
defined $value or die "value is required\n";
|
||||
delete_key(\@L, $section_re, $key, '');
|
||||
add_key(\@L, $section_re, $key, $value);
|
||||
}
|
||||
elsif ($mode eq 'set_masked') {
|
||||
my ($section_re, $key, $mask, $value) = @args;
|
||||
defined $section_re or die "section_re is required\n";
|
||||
defined $key or die "key is required\n";
|
||||
defined $mask or die "mask is required\n";
|
||||
key_del(\@L, $block_re, $key, $mask);
|
||||
defined $value or die "value is required\n";
|
||||
delete_key(\@L, $section_re, $key, $mask);
|
||||
add_key(\@L, $section_re, $key, $value);
|
||||
}
|
||||
elsif ($mode eq 'block_add') {
|
||||
my ($header) = @args;
|
||||
defined $header && length $header or die "block header is required\n";
|
||||
block_add(\@L, $header);
|
||||
elsif ($mode eq 'del_masked') {
|
||||
my ($section_re, $key, $mask) = @args;
|
||||
defined $section_re or die "section_re is required\n";
|
||||
defined $key or die "key is required\n";
|
||||
defined $mask or die "mask is required\n";
|
||||
delete_key(\@L, $section_re, $key, $mask);
|
||||
}
|
||||
elsif ($mode eq 'block_del') {
|
||||
my ($header_re) = @args;
|
||||
defined $header_re && length $header_re or die "block header pattern is required\n";
|
||||
block_del(\@L, $header_re);
|
||||
elsif ($mode eq 'vhost_add') {
|
||||
my ($name) = @args;
|
||||
defined $name && length $name or die "virtual host name is required\n";
|
||||
add_vhost_section(\@L, $name);
|
||||
}
|
||||
elsif ($mode eq 'suspended_list') {
|
||||
print "$_\n" for suspended_list(\@L);
|
||||
exit 0;
|
||||
elsif ($mode eq 'vhost_del') {
|
||||
my ($name) = @args;
|
||||
defined $name && length $name or die "virtual host name is required\n";
|
||||
my $quoted = quotemeta($name);
|
||||
delete_named_section(\@L, "virtualhost\\h+$quoted");
|
||||
}
|
||||
elsif ($mode eq 'suspended_del') {
|
||||
my ($domain) = @args;
|
||||
defined $domain && length $domain or die "domain is required\n";
|
||||
suspended_del(\@L, $domain);
|
||||
elsif ($mode eq 'vhost_down') {
|
||||
my ($name) = @args;
|
||||
defined $name && length $name or die "virtual host name is required\n";
|
||||
suspend_vhost(\@L, $name);
|
||||
}
|
||||
elsif ($mode eq 'suspended_add') {
|
||||
my ($domain) = @args;
|
||||
defined $domain && length $domain or die "domain is required\n";
|
||||
suspended_add(\@L, $domain);
|
||||
elsif ($mode eq 'vhost_up') {
|
||||
my ($name) = @args;
|
||||
defined $name && length $name or die "virtual host name is required\n";
|
||||
unsuspend_vhost(\@L, $name);
|
||||
}
|
||||
elsif ($mode eq 'vhost_list') {
|
||||
my ($type) = @args;
|
||||
vhost_list(\@L, $type // 'all');
|
||||
exit 0;
|
||||
}
|
||||
elsif ($mode eq 'vhost_del') {
|
||||
my ($domain) = @args;
|
||||
defined $domain && length $domain or die "domain is required\n";
|
||||
vhost_del(\@L, $domain);
|
||||
elsif ($mode eq 'vhost_list_map') {
|
||||
my ($type) = @args;
|
||||
vhost_list_map(\@L, $type // 'all');
|
||||
exit 0;
|
||||
}
|
||||
elsif ($mode eq 'vhost_set') {
|
||||
my ($vhRoot, $domain, @aliases) = @args;
|
||||
defined $vhRoot && length $vhRoot or die "vhRoot is required\n";
|
||||
defined $domain && length $domain or die "domain is required\n";
|
||||
vhost_set(\@L, $vhRoot, $domain, @aliases);
|
||||
elsif ($mode eq 'alias_list') {
|
||||
alias_list(\@L);
|
||||
exit 0;
|
||||
}
|
||||
elsif ($mode eq 'vhost_alias') {
|
||||
my ($name) = @args;
|
||||
vhost_alias(\@L, $name);
|
||||
exit 0;
|
||||
}
|
||||
elsif ($mode eq 'member_list') {
|
||||
my ($template, $type) = @args;
|
||||
defined $template && length $template or die "template is required\n";
|
||||
defined $type && length $type or die "type is required\n";
|
||||
member_list(\@L, $template, $type);
|
||||
exit 0;
|
||||
}
|
||||
elsif ($mode eq 'member_del') {
|
||||
my ($template, $domain) = @args;
|
||||
defined $template && length $template or die "template is required\n";
|
||||
defined $domain && length $domain or die "domain is required\n";
|
||||
member_del(\@L, $template, $domain);
|
||||
}
|
||||
elsif ($mode eq 'member_set') {
|
||||
my ($template, $domain, @aliases) = @args;
|
||||
defined $template && length $template or die "template is required\n";
|
||||
defined $domain && length $domain or die "domain is required\n";
|
||||
member_set(\@L, $template, $domain, @aliases);
|
||||
}
|
||||
elsif ($mode eq 'member_alias') {
|
||||
my ($template, $domain) = @args;
|
||||
defined $template && length $template or die "template is required\n";
|
||||
defined $domain && length $domain or die "domain is required\n";
|
||||
member_alias(\@L, $template, $domain);
|
||||
exit 0;
|
||||
}
|
||||
else {
|
||||
die "unknown mode '$mode'\n";
|
||||
}
|
||||
|
||||
$content = join '', @L;
|
||||
$content =~ s/\n{3,}/\n\n/g;
|
||||
|
||||
open my $out, '>', $file or die "cannot write '$file': $!\n";
|
||||
print {$out} $content;
|
||||
|
||||
@@ -30,7 +30,7 @@ function backupSiteFiles() {
|
||||
compressProgram="pigz -p $pigzThreads"
|
||||
fi
|
||||
|
||||
archiveCreate "$olsVhostsPath/$domain" "$file" "$compressProgram"
|
||||
archiveCreate "$vhostsPath/$domain" "$file" "$compressProgram"
|
||||
}
|
||||
|
||||
# Creates a database backup for a site.
|
||||
@@ -83,7 +83,7 @@ function backupSite() {
|
||||
;;
|
||||
esac
|
||||
|
||||
cp -f -- "$olsVhostsConfigPath/$domain.conf" "$path/$domain.conf" || {
|
||||
cp -f -- "$openlitespeedVhostsPath/$domain.conf" "$path/$domain.conf" || {
|
||||
appError "Failed to copy vhost config: $domain"
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -582,7 +582,7 @@ SH
|
||||
|
||||
# Parses the OLS error log since $diagSince and appends categorized error counters to the diag file.
|
||||
function diagOlsErrorSummary() {
|
||||
local openlitespeedErrorLog="$olsLogsPath/error.log"
|
||||
local openlitespeedErrorLog="$openlitespeedLogsPath/error.log"
|
||||
local cutoff
|
||||
|
||||
cutoff="$(diagCutoffEpoch)"
|
||||
|
||||
@@ -163,19 +163,19 @@ function mariadbDatabaseClean() {
|
||||
function mariadbExport() {
|
||||
local execFn="$1"
|
||||
[[ -n "$execFn" ]] || { appError "Exec function not specified"; return 1; }
|
||||
shift || true
|
||||
shift
|
||||
|
||||
local username="$1"
|
||||
[[ -n "$username" ]] || { appError "Username not specified"; return 1; }
|
||||
shift || true
|
||||
shift
|
||||
|
||||
local password="$1"
|
||||
[[ -n "$password" ]] || { appError "Password not specified"; return 1; }
|
||||
shift || true
|
||||
shift
|
||||
|
||||
local database="$1"
|
||||
[[ -n "$database" ]] || { appError "Database not specified"; return 1; }
|
||||
shift || true
|
||||
shift
|
||||
|
||||
local file="$1"
|
||||
if [[ -z "$file" ]]; then
|
||||
@@ -183,7 +183,7 @@ function mariadbExport() {
|
||||
&& file="$appDataPath/$mariadbMasterKube/${appDate}_${appTime}_full.sql.tar.gz" \
|
||||
|| file="$appDataPath/$mariadbMasterKube/${appDate}_${appTime}_$database.sql.tar.gz"
|
||||
fi
|
||||
shift || true
|
||||
shift
|
||||
|
||||
local -a params
|
||||
if [[ $# -gt 0 ]]; then
|
||||
|
||||
@@ -11,8 +11,8 @@ function metricKube() {
|
||||
mkdir -p -- "$metricPromPath" || return 1
|
||||
|
||||
local vhostAllCount vhostUpCount
|
||||
vhostAllCount=$(openlitespeedConfigVhostList all | grep -c . || true)
|
||||
vhostUpCount=$(openlitespeedConfigVhostList up | grep -c . || true)
|
||||
vhostAllCount=$(openlitespeedVhostList all | grep -c . || true)
|
||||
vhostUpCount=$(openlitespeedVhostList up | grep -c . || true)
|
||||
|
||||
local appTimestamp
|
||||
appTimestamp=$(date -d "$appDate ${appTime//-/:}" +%s)
|
||||
@@ -37,8 +37,8 @@ function metricKube() {
|
||||
read -r _req _lim <<< "$_line"
|
||||
slaveMemReq=$(sizeToBytes "$_req"); slaveMemLim=$(sizeToBytes "$_lim")
|
||||
|
||||
_line=$(k3sRun get pods -l "app=$olsKube" \
|
||||
-o jsonpath="{.items[0].spec.containers[?(@.name=='${olsKube}')].resources.requests.memory} {.items[0].spec.containers[?(@.name=='${olsKube}')].resources.limits.memory}" 2>/dev/null)
|
||||
_line=$(k3sRun get pods -l "app=$openlitespeedKube" \
|
||||
-o jsonpath="{.items[0].spec.containers[?(@.name=='${openlitespeedKube}')].resources.requests.memory} {.items[0].spec.containers[?(@.name=='${openlitespeedKube}')].resources.limits.memory}" 2>/dev/null)
|
||||
read -r _req _lim <<< "$_line"
|
||||
olsMemReq=$(sizeToBytes "$_req"); olsMemLim=$(sizeToBytes "$_lim")
|
||||
|
||||
@@ -97,7 +97,7 @@ function metricLsphp() {
|
||||
mkdir -p -- "$metricPromPath" || return 1
|
||||
|
||||
local podList error
|
||||
run podList error k3sPodListStatus "$olsKube" || return 1
|
||||
run podList error k3sPodListStatus "$openlitespeedKube" || return 1
|
||||
|
||||
local pod phase output cpu mem count domain
|
||||
{
|
||||
@@ -110,10 +110,8 @@ function metricLsphp() {
|
||||
|
||||
while IFS='|' read -r pod phase; do
|
||||
[[ "$phase" == "Running" ]] || continue
|
||||
# run output error openlitespeedPodExec "$pod" sh -c "ps aux | grep lsphp | grep -v grep | awk '{u=\$1;cpu[u]+=\$3;mem[u]+=\$4;count[u]++} END {for(u in cpu){name=u;cmd=\"find $olsPodPrivatePath -maxdepth 1 -uid \"u\" -type d 2>/dev/null\";if((cmd|getline dir)>0&&dir!=\"\"){n=split(dir,a,\"/\");name=a[n]};close(cmd);print cpu[u],mem[u],count[u],name}}'" || continue
|
||||
run output error openlitespeedPodExec "$pod" sh -c "ps aux | awk '/lsphp/ && !/nobody/ {u=\$1;cpu[u]+=\$3;mem[u]+=\$4;count[u]++} END {for(u in cpu){name=u;cmd=\"find $olsPodPrivatePath -maxdepth 1 -uid \"u\" -type d 2>/dev/null\";if((cmd|getline dir)>0&&dir!=\"\"){n=split(dir,a,\"/\");name=a[n]};close(cmd);printf \"%.1f\\t%.1f\\t%d\\t%s\\n\",cpu[u],mem[u],count[u],name}}'" || continue
|
||||
|
||||
while IFS=$'\t' read -r cpu mem count domain; do
|
||||
run output error openlitespeedPodExec "$pod" sh -c "ps aux | grep lsphp | grep -v grep | awk '{u=\$1;cpu[u]+=\$3;mem[u]+=\$4;count[u]++} END {for(u in cpu){name=u;cmd=\"find /var/www/data -maxdepth 1 -uid \"u\" -type d 2>/dev/null\";if((cmd|getline dir)>0&&dir!=\"\"){n=split(dir,a,\"/\");name=a[n]};close(cmd);print cpu[u],mem[u],count[u],name}}'" || continue
|
||||
while IFS=' ' read -r cpu mem count domain; do
|
||||
[[ -n "$domain" ]] || continue
|
||||
printf 'lsphp_cpu_percent{domain="%s",pod="%s"} %s\n' "$domain" "$pod" "$cpu"
|
||||
printf 'lsphp_memory_percent{domain="%s",pod="%s"} %s\n' "$domain" "$pod" "$mem"
|
||||
@@ -137,13 +135,13 @@ function metricSites() {
|
||||
dataJson='{}'
|
||||
|
||||
local error vhostList
|
||||
run vhostList error openlitespeedConfigVhostList || {
|
||||
run vhostList error openlitespeedVhostList all || {
|
||||
appError "Error retrieving vhost list: $error"
|
||||
return 1
|
||||
}
|
||||
while IFS= read -r domain <&3; do
|
||||
local diskUsage domainJson
|
||||
diskUsage="$(pathSize "$olsVhostsPath/$domain" "mb" || true)"
|
||||
diskUsage="$(pathSize "$vhostsPath/$domain" "mb" || true)"
|
||||
[[ -n "$diskUsage" ]] || continue
|
||||
|
||||
domainJson="$(
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
# Executes a command inside the OLS deployment container.
|
||||
# $@ (...): command and arguments to execute.
|
||||
function openlitespeedExec() {
|
||||
k3sRun exec deploy/"$olsKube" -c "$olsKube" -- "$@"
|
||||
}
|
||||
# [ Config editor ] ===========================================================
|
||||
|
||||
# Executes a command inside a specific OLS pod.
|
||||
# $1 (pod): pod name.
|
||||
# $2+ (...): command and arguments to execute.
|
||||
function openlitespeedPodExec() {
|
||||
local pod="$1"
|
||||
[[ -n "$pod" ]] || { appError "Pod not specified"; return 1; }
|
||||
shift || true
|
||||
# Normalizes an OpenLiteSpeed configuration file.
|
||||
# Collapses three or more consecutive blank lines into two.
|
||||
# [$1] (file): config file path (defaults to $openlitespeedConfigFile).
|
||||
function openlitespeedConfigNormalize() {
|
||||
local file="${1:-$openlitespeedConfigFile}"
|
||||
[[ -n "$file" ]] || { appError "Config file not specified"; return 1; }
|
||||
|
||||
k3sRun exec pod/"$pod" -c "$olsKube" -- "$@"
|
||||
perl -0pi -e 's/\n{3,}/\n\n/g' "$file" || {
|
||||
appError "Failed normalize config file: $file"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
# Edits an OpenLiteSpeed configuration file via the OLS config editor script.
|
||||
@@ -36,313 +34,118 @@ function openlitespeedConfigEditFile() {
|
||||
# Edits the main OLS config file.
|
||||
# $@ (...): edit mode and arguments.
|
||||
function openlitespeedConfigEdit() {
|
||||
openlitespeedConfigEditFile "$olsConfigFile" "$@"
|
||||
openlitespeedConfigEditFile "$openlitespeedConfigFile" "$@"
|
||||
}
|
||||
|
||||
# Adds a value to the main OLS config.
|
||||
function openlitespeedConfigKeyAdd() {
|
||||
openlitespeedConfigEdit key_add "$@"
|
||||
}
|
||||
|
||||
# Sets a value in the main OLS config.
|
||||
function openlitespeedConfigKeySet() {
|
||||
openlitespeedConfigEdit key_set "$@"
|
||||
}
|
||||
|
||||
# Sets a masked value in the main OLS config.
|
||||
function openlitespeedConfigKeyMaskSet() {
|
||||
openlitespeedConfigEdit key_mask_set "$@"
|
||||
# Edits the OLS WebAdmin config file.
|
||||
# $@ (...): edit mode and arguments.
|
||||
function openlitespeedAdminConfigEdit() {
|
||||
openlitespeedConfigEditFile "$openlitespeedAdminPath/admin_config.conf" "$@"
|
||||
}
|
||||
|
||||
# Deletes a value from the main OLS config.
|
||||
function openlitespeedConfigKeyDel() {
|
||||
openlitespeedConfigEdit key_del "$@"
|
||||
function openlitespeedConfigEditDel() {
|
||||
openlitespeedConfigEdit del "$@"
|
||||
}
|
||||
|
||||
# Deletes masked values from the main OLS config.
|
||||
function openlitespeedConfigKeyMaskDel() {
|
||||
openlitespeedConfigEdit key_mask_del "$@"
|
||||
function openlitespeedConfigEditDelMasked() {
|
||||
openlitespeedConfigEdit del_masked "$@"
|
||||
}
|
||||
|
||||
# Adds a generic section to the main OLS config.
|
||||
# $1 (header): section header text, e.g. "listener HTTP".
|
||||
function openlitespeedConfigBlockAdd() {
|
||||
openlitespeedConfigEdit block_add "$@"
|
||||
# Adds a value to the main OLS config.
|
||||
function openlitespeedConfigEditAdd() {
|
||||
openlitespeedConfigEdit add "$@"
|
||||
}
|
||||
|
||||
# Deletes a generic section from the main OLS config.
|
||||
# $1 (header_re): regex pattern matching the section header.
|
||||
function openlitespeedConfigBlockDel() {
|
||||
openlitespeedConfigEdit block_del "$@"
|
||||
# Sets a value in the main OLS config.
|
||||
function openlitespeedConfigEditSet() {
|
||||
openlitespeedConfigEdit set "$@"
|
||||
}
|
||||
|
||||
# Sets a masked value in the main OLS config.
|
||||
function openlitespeedConfigEditSetMasked() {
|
||||
openlitespeedConfigEdit set_masked "$@"
|
||||
}
|
||||
|
||||
# Adds a virtual host entry to the main OLS config.
|
||||
# $1 (domain): virtual host name.
|
||||
function openlitespeedConfigVHostAdd() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
openlitespeedConfigEdit vhost_add "$domain"
|
||||
}
|
||||
|
||||
# Deletes a virtual host entry from the main OLS config.
|
||||
# $1 (domain): virtual host name.
|
||||
function openlitespeedConfigVHostDel() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
openlitespeedConfigEdit vhost_del "$domain"
|
||||
}
|
||||
|
||||
# Sets a value in the OLS WebAdmin config.
|
||||
function openlitespeedAdminConfigEditSet() {
|
||||
openlitespeedAdminConfigEdit set "$@"
|
||||
}
|
||||
|
||||
# Lists OLS virtual hosts filtered by state.
|
||||
# [$1] (type): filter type: all, up, or down (defaults to all).
|
||||
function openlitespeedConfigVhostList() {
|
||||
function openlitespeedVhostList() {
|
||||
local type="${1:-all}"
|
||||
arrayContains "$type" "all" "up" "down" || { appError "Unknown type: $type"; return 1; }
|
||||
|
||||
case "$olsVhostMode" in
|
||||
standalone) openlitespeedConfigEdit vhost_list "$type" || return 1 ;;
|
||||
template) openlitespeedConfigEdit member_list "$olsVhostTemplate" "$type" || return 1 ;;
|
||||
esac
|
||||
openlitespeedConfigEdit vhost_list "$type"
|
||||
}
|
||||
|
||||
function openlitespeedConfigVhostSet() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
shift
|
||||
|
||||
case "$olsVhostMode" in
|
||||
# standalone) openlitespeedConfigEdit vhost_set "$olsPodVhostsPath/$domain" "$domain" "$@" || return 1 ;;
|
||||
standalone) openlitespeedConfigEdit vhost_set "$olsPodVhostsPath/\$VH_NAME" "$domain" "$@" || return 1 ;;
|
||||
template) openlitespeedConfigEdit member_set "$olsVhostTemplate" "$domain" "$@" || return 1 ;;
|
||||
esac
|
||||
# Lists OLS virtual hosts with their map entries, filtered by state.
|
||||
# [$1] (type): filter type: all, up, or down (defaults to all).
|
||||
function openlitespeedVhostListMap() {
|
||||
local type="${1:-all}"
|
||||
arrayContains "$type" "all" "up" "down" || { appError "Unknown type: $type"; return 1; }
|
||||
openlitespeedConfigEdit vhost_list_map "$type"
|
||||
}
|
||||
|
||||
# Deletes a virtual host entry from the main OLS config.
|
||||
function openlitespeedConfigVhostDel() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
case "$olsVhostMode" in
|
||||
standalone) openlitespeedConfigEdit vhost_del "$domain" || return 1 ;;
|
||||
template) openlitespeedConfigEdit member_del "$olsVhostTemplate" "$domain" || return 1 ;;
|
||||
esac
|
||||
# Lists configured OLS aliases.
|
||||
function openlitespeedAliasList() {
|
||||
openlitespeedConfigEdit alias_list
|
||||
}
|
||||
|
||||
# Lists aliases assigned to a virtual host.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedConfigVhostAliasList() {
|
||||
function openlitespeedVhostAlias() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
case "$olsVhostMode" in
|
||||
standalone) openlitespeedConfigEdit vhost_alias "$domain" || return 1 ;;
|
||||
template) openlitespeedConfigEdit member_alias "$olsVhostTemplate" "$domain" || return 1 ;;
|
||||
esac
|
||||
openlitespeedConfigEdit vhost_alias "$domain"
|
||||
}
|
||||
|
||||
# Lists configured OLS aliases.
|
||||
function openlitespeedConfigAliasList() {
|
||||
case "$olsVhostMode" in
|
||||
standalone) openlitespeedConfigEdit vhost_alias all || return 1 ;;
|
||||
template) openlitespeedConfigEdit member_alias "$olsVhostTemplate" all || return 1 ;;
|
||||
esac
|
||||
# Executes a command inside the OLS deployment container.
|
||||
# $@ (...): command and arguments to execute.
|
||||
function openlitespeedExec() {
|
||||
k3sRun exec deploy/"$openlitespeedKube" -c "$openlitespeedKube" -- "$@"
|
||||
}
|
||||
|
||||
# Marks a virtual host as active.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedConfigVhostUp() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
openlitespeedConfigEdit suspended_del "$domain" || return 1
|
||||
}
|
||||
# Executes a command inside a specific OLS pod.
|
||||
# $1 (pod): pod name.
|
||||
# $2+ (...): command and arguments to execute.
|
||||
function openlitespeedPodExec() {
|
||||
local pod="$1"
|
||||
[[ -n "$pod" ]] || { appError "Pod not specified"; return 1; }
|
||||
shift
|
||||
|
||||
# Marks a virtual host as suspended.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedConfigVhostDown() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
openlitespeedConfigEdit suspended_add "$domain" || return 1
|
||||
}
|
||||
|
||||
function openlitespeedConfigRebuild() {
|
||||
local children php block
|
||||
children=$(configGet "$appAssetsPath/openlitespeed/profiles/memory-$kubeMemoryProfile.config" "children")
|
||||
|
||||
fileBackup "$olsConfigFile"
|
||||
|
||||
openlitespeedConfigBlockDel "wsgiDefaults"
|
||||
openlitespeedConfigBlockDel "nodeDefaults"
|
||||
openlitespeedConfigBlockDel "railsDefaults"
|
||||
openlitespeedConfigBlockDel "vh[Tt]emplate\h+centralConfigLog"
|
||||
openlitespeedConfigBlockDel "vh[Tt]emplate\h+EasyRailsWithSuEXEC"
|
||||
openlitespeedConfigBlockDel "vh[Tt]emplate\h+docker"
|
||||
openlitespeedConfigBlockDel "listener\h+Default"
|
||||
openlitespeedConfigBlockDel "virtual[Hh]ost\h+Example"
|
||||
openlitespeedConfigKeySet '' 'useIpInProxyHeader' '2'
|
||||
openlitespeedConfigKeySet 'fileAccessControl' 'checkSymbolLink' '1'
|
||||
openlitespeedConfigKeySet 'accessControl' 'deny' ''
|
||||
openlitespeedConfigKeySet 'accessControl' 'allow' '10.42.0.0/16T, 10.43.0.0/16T'
|
||||
|
||||
local phpList=("" "${olsPhpList[@]}")
|
||||
for php in "${phpList[@]}"; do
|
||||
block="extProcessor lsphp$php"
|
||||
openlitespeedConfigBlockDel "ext[Pp]rocessor lsphp$php"
|
||||
openlitespeedConfigBlockAdd "$block"
|
||||
openlitespeedConfigKeyAdd "$block" 'type' 'lsapi'
|
||||
openlitespeedConfigKeyAdd "$block" 'address' "uds://tmp/lshttpd/lsphp$php.sock"
|
||||
openlitespeedConfigKeyAdd "$block" 'path' "/usr/local/lsws/lsphp$php/bin/lsphp"
|
||||
openlitespeedConfigKeyAdd "$block" 'maxConns' "$children"
|
||||
openlitespeedConfigKeyAdd "$block" 'env' "PHP_LSAPI_CHILDREN=$children"
|
||||
openlitespeedConfigKeyAdd "$block" 'env' 'PHP_INI_SCAN_DIR=:/etc/ols-php-ini:/var/www/private/$VH_NAME/php'
|
||||
openlitespeedConfigKeyAdd "$block" 'env' 'LSAPI_AVOID_FORK=0'
|
||||
openlitespeedConfigKeyAdd "$block" 'env' 'LSAPI_MAX_IDLE=120'
|
||||
openlitespeedConfigKeyAdd "$block" 'env' 'LSAPI_MAX_IDLE_CHILDREN=1'
|
||||
openlitespeedConfigKeyAdd "$block" 'env' 'LSAPI_PGRP_MAX_IDLE=300'
|
||||
openlitespeedConfigKeyAdd "$block" 'env' 'LSAPI_MAX_PROCESS_TIME=300'
|
||||
openlitespeedConfigKeyAdd "$block" 'env' 'LSAPI_SLOW_REQ_MSECS=5000'
|
||||
openlitespeedConfigKeyAdd "$block" 'initTimeout' '60'
|
||||
openlitespeedConfigKeyAdd "$block" 'retryTimeout' '0'
|
||||
openlitespeedConfigKeyAdd "$block" 'persistConn' '1'
|
||||
openlitespeedConfigKeyAdd "$block" 'respBuffer' '0'
|
||||
openlitespeedConfigKeyAdd "$block" 'autoStart' '2'
|
||||
openlitespeedConfigKeyAdd "$block" 'backlog' '100'
|
||||
openlitespeedConfigKeyAdd "$block" 'instances' '1'
|
||||
openlitespeedConfigKeyAdd "$block" 'priority' '0'
|
||||
openlitespeedConfigKeyAdd "$block" 'memSoftLimit' '0'
|
||||
openlitespeedConfigKeyAdd "$block" 'memHardLimit' '0'
|
||||
openlitespeedConfigKeyAdd "$block" 'procSoftLimit' '700'
|
||||
openlitespeedConfigKeyAdd "$block" 'procHardLimit' '800'
|
||||
|
||||
openlitespeedConfigKeyAdd "script[Hh]andler" add "lsapi:lsphp$php lsphp$php"
|
||||
done
|
||||
openlitespeedConfigKeySet "extProcessor\h+lsphp" 'path' 'fcgi-bin/lsphp'
|
||||
|
||||
# module cache
|
||||
block="module cache"
|
||||
openlitespeedConfigBlockDel "module\h+cache"
|
||||
openlitespeedConfigBlockAdd "$block"
|
||||
openlitespeedConfigKeyAdd "$block" 'ls_enabled' '1'
|
||||
openlitespeedConfigKeyAdd "$block" 'checkPrivateCache' '1'
|
||||
openlitespeedConfigKeyAdd "$block" 'checkPublicCache' '1'
|
||||
openlitespeedConfigKeyAdd "$block" 'maxCacheObjSize' '10000000'
|
||||
openlitespeedConfigKeyAdd "$block" 'maxStaleAge' '200'
|
||||
openlitespeedConfigKeyAdd "$block" 'qsCache' '1'
|
||||
openlitespeedConfigKeyAdd "$block" 'reqCookieCache' '1'
|
||||
openlitespeedConfigKeyAdd "$block" 'respCookieCache' '1'
|
||||
openlitespeedConfigKeyAdd "$block" 'ignoreReqCacheCtrl' '1'
|
||||
openlitespeedConfigKeyAdd "$block" 'ignoreRespCacheCtrl' '0'
|
||||
openlitespeedConfigKeyAdd "$block" 'enableCache' '0'
|
||||
openlitespeedConfigKeyAdd "$block" 'expireInSeconds' '3600'
|
||||
openlitespeedConfigKeyAdd "$block" 'enablePrivateCache' '0'
|
||||
openlitespeedConfigKeyAdd "$block" 'privateExpireInSeconds' '3600'
|
||||
}
|
||||
|
||||
function openlitespeedVhostSet() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
shift || true
|
||||
|
||||
local -a aliasesRaw=("$@")
|
||||
local -a aliases=()
|
||||
local aliasRaw alias error
|
||||
for aliasRaw in "${aliasesRaw[@]}"; do
|
||||
alias="$(domainPrepare "$aliasRaw")"
|
||||
[[ -n "$alias" ]] || continue
|
||||
[[ "$alias" == "$domain" ]] && continue
|
||||
runError error domainCheck "$alias" || { appError "$alias: $error"; return 1; }
|
||||
arrayContains "$alias" "${aliases[@]}" || aliases+=("$alias")
|
||||
done
|
||||
|
||||
local vhostAliasList vhostList aliasList
|
||||
run vhostAliasList error openlitespeedConfigVhostAliasList "$domain" || { appError "Failed get list of vhost alias: $error"; return 1; }
|
||||
run vhostList error openlitespeedConfigVhostList || { appError "Failed get list of vhost: $error"; return 1; }
|
||||
run aliasList error openlitespeedConfigAliasList || { appError "Failed get list of alias: $error"; return 1; }
|
||||
|
||||
# For a new domain vhostAliasList is empty, so this covers both create and update
|
||||
local aliasListOther
|
||||
aliasListOther=$(grep -Fvx -f <(printf '%s\n' "$vhostAliasList") <<< "$aliasList" || true)
|
||||
for alias in "${aliases[@]}"; do
|
||||
listContains "$alias" "$vhostList" && { appError "$alias: Is already exists as vhost"; return 1; }
|
||||
listContains "$alias" "$aliasListOther" && { appError "$alias: Is already exists as alias"; return 1; }
|
||||
done
|
||||
|
||||
local aliasValue=''
|
||||
[[ ${#aliases[@]} -gt 0 ]] && aliasValue="$(IFS=','; printf '%s\n' "${aliases[*]}")"
|
||||
|
||||
fileBackup "$olsConfigFile" || return 1
|
||||
openlitespeedConfigVhostSet "$domain" "${aliases[@]}" || return 1
|
||||
|
||||
local domainConfigFile="$appDataPath/config/$domain.config"
|
||||
configSet "$domainConfigFile" alias "$aliasValue" || { appError "Failed set alias in $domainConfigFile"; return 1; }
|
||||
|
||||
if [[ "$olsVhostMode" == "standalone" ]]; then
|
||||
local vHostFile="$olsVhostsConfigPath/$domain.conf"
|
||||
if [[ ! -f "$vHostFile" ]]; then
|
||||
local profileFile memory_limit max_execution_time post_max_size upload_max_filesize
|
||||
profileFile="$appAssetsPath/openlitespeed/profiles/memory-$kubeMemoryProfile.config"
|
||||
[[ -f "$profileFile" ]] || { appError "Profile not found: $profileFile"; return 1; }
|
||||
memory_limit=$(configGet "$profileFile" "memory_limit")
|
||||
max_execution_time=$(configGet "$profileFile" "max_execution_time")
|
||||
post_max_size=$(configGet "$profileFile" "post_max_size")
|
||||
upload_max_filesize=$(configGet "$profileFile" "upload_max_filesize")
|
||||
|
||||
# cp -f -- "$appAssetsPath/openlitespeed/vhost.conf" "$vHostFile" || { appError "Copy vhost template failed"; return 1; }
|
||||
# -e "s|{{domain}}|$domain|g" \
|
||||
cp -f -- "$appAssetsPath/openlitespeed/vhosts/$olsVhostFile" "$vHostFile" || { appError "Copy vhost template failed"; return 1; }
|
||||
sed -i \
|
||||
-e "s|{{memory_limit}}|$memory_limit|g" \
|
||||
-e "s|{{max_execution_time}}|$max_execution_time|g" \
|
||||
-e "s|{{post_max_size}}|$post_max_size|g" \
|
||||
-e "s|{{upload_max_filesize}}|$upload_max_filesize|g" \
|
||||
-- "$vHostFile" || { appError "Template substitution failed: $vHostFile"; return 1; }
|
||||
fi
|
||||
fi
|
||||
|
||||
printf '%s' "$aliasValue"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Removes a virtual host from the OLS main config, listener map, and config files.
|
||||
# Idempotent: safe to call even if the vhost does not exist.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedVhostConfigDel() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
fileBackup "$olsConfigFile" || return 1
|
||||
openlitespeedConfigVhostUp "$domain"
|
||||
openlitespeedConfigVhostDel "$domain"
|
||||
|
||||
if [[ "$olsVhostMode" == "standalone" ]]; then
|
||||
rm -f -- "$olsVhostsConfigPath/$domain.conf" &>/dev/null
|
||||
rm -f -- "$olsVhostsConfigPath/$domain.conf0" &>/dev/null
|
||||
rm -f -- "$olsVhostsConfigPath/$domain.txt" &>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# Marks a virtual host as active.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedVhostConfigUp() {
|
||||
local domain vhostList error
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
run vhostList error openlitespeedConfigVhostList || return 1
|
||||
listContains "$domain" "$vhostList" || return 1
|
||||
|
||||
openlitespeedConfigVhostUp "$domain"
|
||||
}
|
||||
|
||||
# Marks a virtual host as suspended.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedVhostConfigDown() {
|
||||
local domain vhostList error
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
run vhostList error openlitespeedConfigVhostList || return 1
|
||||
runSilent fileCheckLineLength "$olsConfigFile" 8000 || { appError "fileCheckLineLength 8000"; return 1; }
|
||||
listContains "$domain" "$vhostList" || return 1
|
||||
|
||||
openlitespeedConfigVhostDown "$domain"
|
||||
k3sRun exec pod/"$pod" -c "$openlitespeedKube" -- "$@"
|
||||
}
|
||||
|
||||
# Rebuilds filesystem layout, ownership, and permissions for a virtual host.
|
||||
# $1 (vhostPath): virtual host chroot path.
|
||||
# $2 (privatePath): virtual host private path.
|
||||
# $2 (vhostDataPath): virtual host data path.
|
||||
# $3 (ug): system user/group name for the site.
|
||||
function openlitespeedVhostPermissionSet() {
|
||||
function openlitespeedVhostRebuildPath() {
|
||||
local vhostPath="$1"
|
||||
local privatePath="$2"
|
||||
local vhostDataPath="$2"
|
||||
local ug="$3"
|
||||
[[ -n "$vhostPath" ]] || { appError "vhostPath not specified"; return 1; }
|
||||
[[ -n "$privatePath" ]] || { appError "privatePath not specified"; return 1; }
|
||||
[[ -n "$ug" ]] || { appError "ug not specified"; return 1; }
|
||||
[[ -n "$vhostPath" ]] || { appError "vhostPath not specified"; return 1; }
|
||||
[[ -n "$vhostDataPath" ]] || { appError "vhostDataPath not specified"; return 1; }
|
||||
[[ -n "$ug" ]] || { appError "ug not specified"; return 1; }
|
||||
|
||||
# Create site directories
|
||||
mkdir -p -- "$vhostPath"/{www,tmp,session} || { appError "Create vhost directories failed: $vhostPath"; return 1; }
|
||||
@@ -367,23 +170,22 @@ function openlitespeedVhostPermissionSet() {
|
||||
find "$vhostPath/session" -type f -exec chmod 600 -- {} + || { appError "Change permissions of session files failed"; return 1; }
|
||||
|
||||
# Vhost data directory and bootstrap.php
|
||||
mkdir -p -- "$privatePath" || { appError "Create vhost private directory failed: $privatePath"; return 1; }
|
||||
# mkdir -p -- "$privatePath/php" || { appError "Create vhost private/php directory failed: $privatePath"; return 1; }
|
||||
touch -- "$privatePath/bootstrap.php" || { appError "Create bootstrap.php failed: $privatePath/bootstrap.php"; return 1; }
|
||||
chown -R -- "$ug:$ug" "$privatePath" || { appError "Change owner of vhost private directory failed: $privatePath"; return 1; }
|
||||
find "$privatePath" -type d -exec chmod 700 -- {} + || { appError "Change permissions of vhost private directories failed"; return 1; }
|
||||
find "$privatePath" -type f -exec chmod 600 -- {} + || { appError "Change permissions of vhost private files failed"; return 1; }
|
||||
mkdir -p -- "$vhostDataPath" || { appError "Create vhost data directory failed: $vhostDataPath"; return 1; }
|
||||
touch -- "$vhostDataPath/bootstrap.php" || { appError "Create bootstrap.php failed: $vhostDataPath/bootstrap.php"; return 1; }
|
||||
chown -R -- "$ug:$ug" "$vhostDataPath" || { appError "Change owner of vhost data directory failed: $vhostDataPath"; return 1; }
|
||||
find "$vhostDataPath" -type d -exec chmod 700 -- {} + || { appError "Change permissions of vhost data directories failed"; return 1; }
|
||||
find "$vhostDataPath" -type f -exec chmod 600 -- {} + || { appError "Change permissions of vhost data files failed"; return 1; }
|
||||
}
|
||||
|
||||
# Rebuilds ACL rules for a virtual host.
|
||||
# Resets existing ACLs, then grants OLS nobody user read access to www/data and rw to tmp/session.
|
||||
# $1 (vhostPath): virtual host chroot path.
|
||||
# $2 (privatePath): virtual host private path.
|
||||
function openlitespeedVhostAclSet() {
|
||||
# $2 (vhostDataPath): virtual host data path.
|
||||
function openlitespeedVhostRebuildACL() {
|
||||
local vhostPath="$1"
|
||||
local privatePath="$2"
|
||||
[[ -n "$vhostPath" ]] || { appError "vhostPath not specified"; return 1; }
|
||||
[[ -n "$privatePath" ]] || { appError "privatePath not specified"; return 1; }
|
||||
local vhostDataPath="$2"
|
||||
[[ -n "$vhostPath" ]] || { appError "vhostPath not specified"; return 1; }
|
||||
[[ -n "$vhostDataPath" ]] || { appError "vhostDataPath not specified"; return 1; }
|
||||
|
||||
# ACL reset: vhostPath
|
||||
setfacl -R -b -- "$vhostPath" || { appError "Clean ACL rules for vhost path failed: $vhostPath"; return 1; }
|
||||
@@ -399,25 +201,70 @@ function openlitespeedVhostAclSet() {
|
||||
find "$vhostPath/tmp" "$vhostPath/session" -type d -exec setfacl -m u:nobody:rwx,m:rwx,d:u:nobody:rwx,d:m:rwx -- {} + || { appError "Set ACL for nobody on tmp/session directories failed"; return 1; }
|
||||
find "$vhostPath/tmp" "$vhostPath/session" -type f -exec setfacl -m u:nobody:rw,m:rw -- {} + || { appError "Set ACL for nobody on tmp/session files failed"; return 1; }
|
||||
|
||||
# ACL reset: privatePath
|
||||
setfacl -R -b -- "$privatePath" || { appError "Clean ACL rules for vhost private path failed: $privatePath"; return 1; }
|
||||
find "$privatePath" -type d -exec setfacl -k -- {} + || { appError "Clean default ACL rules for vhost private directories failed: $privatePath"; return 1; }
|
||||
# ACL reset: vhostDataPath
|
||||
setfacl -R -b -- "$vhostDataPath" || { appError "Clean ACL rules for vhost data path failed: $vhostDataPath"; return 1; }
|
||||
find "$vhostDataPath" -type d -exec setfacl -k -- {} + || { appError "Clean default ACL rules for vhost data directories failed: $vhostDataPath"; return 1; }
|
||||
|
||||
# ACL for OLS user nobody: privatePath
|
||||
find "$privatePath" -type d -exec setfacl -m u:nobody:rx,m:rx,d:u:nobody:rx,d:m:rx -- {} + || { appError "Set ACL for nobody on vhost private directories failed"; return 1; }
|
||||
find "$privatePath" -type f -exec setfacl -m u:nobody:r,m:r -- {} + || { appError "Set ACL for nobody on vhost private files failed"; return 1; }
|
||||
# ACL for OLS user nobody: vhostDataPath
|
||||
find "$vhostDataPath" -type d -exec setfacl -m u:nobody:rx,m:rx,d:u:nobody:rx,d:m:rx -- {} + || { appError "Set ACL for nobody on vhost data directories failed"; return 1; }
|
||||
find "$vhostDataPath" -type f -exec setfacl -m u:nobody:r,m:r -- {} + || { appError "Set ACL for nobody on vhost data files failed"; return 1; }
|
||||
}
|
||||
|
||||
# Sets user disk and inode quota for a virtual host.
|
||||
# Requires user quota to be already enabled and active on the target filesystem.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedVhostRebuildQuota() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local ug
|
||||
ug=$(domainToUser "$domain")
|
||||
|
||||
local quotaMount
|
||||
quotaMount=$(findmnt -no TARGET --target "$vhostsPath")
|
||||
[[ -n "$quotaMount" ]] || { appError "Quota mount not found: $vhostsPath"; return 1; }
|
||||
|
||||
local quotaBlockLimit quotaInodeLimit
|
||||
quotaBlockLimit=$(siteConfigGetOrSet "$domain" "quotaBlockLimit" "$openlitespeedQuotaBlockLimit")
|
||||
quotaInodeLimit=$(siteConfigGetOrSet "$domain" "quotaInodeLimit" "$openlitespeedQuotaInodeLimit")
|
||||
setquota -u "$ug" "$quotaBlockLimit" "$quotaBlockLimit" "$quotaInodeLimit" "$quotaInodeLimit" "$quotaMount" || {
|
||||
appError "Set quota failed: ug=$ug mount=$quotaMount"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
# Checks whether user quota support is ready on the virtual host filesystem.
|
||||
function openlitespeedQuotaCheck() {
|
||||
local quotaMount
|
||||
quotaMount=$(findmnt -no TARGET --target "$vhostsPath")
|
||||
[[ -n "$quotaMount" ]] || { appError "Quota mount not found: $vhostsPath"; return 1; }
|
||||
|
||||
local quotaOptions
|
||||
quotaOptions=$(findmnt -no OPTIONS --target "$quotaMount")
|
||||
[[ "$quotaOptions" == *usrquota* || "$quotaOptions" == *uquota* ]] || {
|
||||
appError "User quota is not enabled: mount=$quotaMount options=$quotaOptions"
|
||||
return 1
|
||||
}
|
||||
|
||||
quotaon -p "$quotaMount" 2>/dev/null | grep -qi "user quota on" || {
|
||||
appError "User quota is not active: mount=$quotaMount"
|
||||
return 1
|
||||
}
|
||||
|
||||
command -v setquota >/dev/null 2>&1 || { appError "setquota command not found"; return 1; }
|
||||
}
|
||||
|
||||
# Prints disk and inode quota hard limits for a user on the virtual host filesystem.
|
||||
# Output format: <blockLimit> <inodeLimit>
|
||||
# $1 (user): username or numeric UID.
|
||||
function openlitespeedVhostQuotaGet() {
|
||||
function openlitespeedVhostQuota() {
|
||||
local user="$1"
|
||||
[[ -n "$user" ]] || { appError "User not specified"; return 1; }
|
||||
|
||||
local quotaMount
|
||||
quotaMount=$(findmnt -no TARGET --target "$olsVhostsPath")
|
||||
[[ -n "$quotaMount" ]] || { appError "Quota mount not found: $olsVhostsPath"; return 1; }
|
||||
quotaMount=$(findmnt -no TARGET --target "$vhostsPath")
|
||||
[[ -n "$quotaMount" ]] || { appError "Quota mount not found: $vhostsPath"; return 1; }
|
||||
|
||||
local quotaLimits error
|
||||
run quotaLimits error quota -u "$user" --filesystem "$quotaMount" || { appError "$error"; return 1; }
|
||||
@@ -427,35 +274,11 @@ function openlitespeedVhostQuotaGet() {
|
||||
printf '%s\n' "$quotaLimits"
|
||||
}
|
||||
|
||||
# Sets user disk and inode quota for a virtual host.
|
||||
# Requires user quota to be already enabled and active on the target filesystem.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedVhostQuotaSet() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local ug
|
||||
ug=$(domainToUser "$domain")
|
||||
|
||||
local quotaMount
|
||||
quotaMount=$(findmnt -no TARGET --target "$olsVhostsPath")
|
||||
[[ -n "$quotaMount" ]] || { appError "Quota mount not found: $olsVhostsPath"; return 1; }
|
||||
|
||||
local quotaBlockLimit quotaInodeLimit
|
||||
quotaBlockLimit=$(siteConfigGetOrSet "$domain" "quotaBlockLimit" "$olsQuotaBlockLimit")
|
||||
quotaInodeLimit=$(siteConfigGetOrSet "$domain" "quotaInodeLimit" "$olsQuotaInodeLimit")
|
||||
setquota -u "$ug" "$quotaBlockLimit" "$quotaBlockLimit" "$quotaInodeLimit" "$quotaInodeLimit" "$quotaMount" || {
|
||||
appError "Set quota failed: ug=$ug mount=$quotaMount"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
# Configures XFS project quota for a virtual host.
|
||||
# $1 (vhostPath): virtual host path to assign to an XFS project.
|
||||
# $2 (projectId): numeric XFS project ID.
|
||||
# $3 (projectName): XFS project name.
|
||||
function openlitespeedVhostXfsSet() {
|
||||
function openlitespeedVhostRebuildXFS() {
|
||||
local vhostPath="$1"
|
||||
local projectId="$2"
|
||||
local projectName="$3"
|
||||
@@ -474,7 +297,7 @@ function openlitespeedVhostXfsSet() {
|
||||
quotaMount=$(findmnt -no TARGET --target "$vhostPath")
|
||||
[[ -n "$quotaMount" ]] || { appError "Detect XFS quota mount failed: $vhostPath"; return 1; }
|
||||
[[ "$quotaMount" == '/' || "$vhostPath" == "$quotaMount"/* ]] || {
|
||||
appError "XFS quota mount mismatch: vhostPath=$vhostPath quotaMount=$quotaMount expected=$olsVhostsPath"
|
||||
appError "XFS quota mount mismatch: vhostPath=$vhostPath quotaMount=$quotaMount expected=$vhostsPath"
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -512,10 +335,10 @@ function openlitespeedVhostRebuild() {
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local ug vhostPath privatePath
|
||||
local ug vhostPath vhostDataPath
|
||||
ug=$(domainToUser "$domain")
|
||||
vhostPath="$olsVhostsPath/$domain"
|
||||
privatePath="$olsPrivatePath/$domain"
|
||||
vhostPath="$vhostsPath/$domain"
|
||||
vhostDataPath="$openlitespeedVhostDataPath/$domain"
|
||||
|
||||
# User and group
|
||||
if ! getent group "$ug" >/dev/null 2>&1; then
|
||||
@@ -527,39 +350,158 @@ function openlitespeedVhostRebuild() {
|
||||
usermod -g "$ug" -d "$vhostPath" -s /usr/sbin/nologin -- "$ug" >/dev/null 2>&1 || { appError "Update user failed: $ug"; return 1; }
|
||||
fi
|
||||
|
||||
openlitespeedVhostPermissionSet "$vhostPath" "$privatePath" "$ug" || return 1
|
||||
openlitespeedVhostAclSet "$vhostPath" "$privatePath" || return 1
|
||||
openlitespeedVhostRebuildPath "$vhostPath" "$vhostDataPath" "$ug" || return 1
|
||||
openlitespeedVhostRebuildACL "$vhostPath" "$vhostDataPath" || return 1
|
||||
|
||||
# Quota
|
||||
# openlitespeedVhostQuotaSet "$domain" || return 1
|
||||
# openlitespeedVhostRebuildQuota "$domain" || return 1
|
||||
|
||||
# XFS [ NO USE ! | Only for XFS + prjquota ]
|
||||
# local uId
|
||||
# uId=$(id -u "$ug" 2>/dev/null)
|
||||
# [[ -n "$uId" ]] || { appError "Get user id failed: $ug"; return 1; }
|
||||
# openlitespeedVhostXfsSet "$vhostPath" "$uId" "$domain" || return 1
|
||||
# openlitespeedVhostRebuildXFS "$vhostPath" "$uId" "$domain" || return 1
|
||||
}
|
||||
|
||||
# Edits the OLS WebAdmin config file.
|
||||
# $@ (...): edit mode and arguments.
|
||||
function openlitespeedAdminConfigEdit() {
|
||||
openlitespeedConfigEditFile "$olsAdminPath/admin_config.conf" "$@"
|
||||
# Creates or deletes OLS config entries for a virtual host.
|
||||
# On create, generates the vhost config file from template if it does not exist.
|
||||
# $1 (domain): site domain name.
|
||||
# [$2] (option): action: create or delete (defaults to create).
|
||||
function openlitespeedConfigRebuild() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local option="${2:-create}"
|
||||
case "$option" in
|
||||
create|delete) ;;
|
||||
*)
|
||||
appError "Unknown option: $option"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
fileBackup "$openlitespeedConfigFile" || return 1
|
||||
|
||||
openlitespeedConfigVHostDel "$domain" || return 1
|
||||
|
||||
local vHostFile="$openlitespeedVhostsPath/$domain.conf"
|
||||
if [[ "$option" == "create" ]]; then
|
||||
openlitespeedConfigEditAdd 'listener\h+HTTP' map "$domain $domain" || return 1
|
||||
openlitespeedConfigVHostAdd "$domain" || return 1
|
||||
|
||||
if [[ ! -f "$vHostFile" ]]; then
|
||||
local profileFile memory_limit max_execution_time post_max_size upload_max_filesize
|
||||
profileFile="$appAssetsPath/openlitespeed/profiles/memory-$kubeMemoryProfile.config"
|
||||
[[ -f "$profileFile" ]] || { appError "Profile not found: $profileFile"; return 1; }
|
||||
memory_limit=$(configGet "$profileFile" "memory_limit")
|
||||
max_execution_time=$(configGet "$profileFile" "max_execution_time")
|
||||
post_max_size=$(configGet "$profileFile" "post_max_size")
|
||||
upload_max_filesize=$(configGet "$profileFile" "upload_max_filesize")
|
||||
|
||||
cp -f -- "$appAssetsPath/openlitespeed/vhost.conf" "$vHostFile" || { appError "Copy vhost template failed"; return 1; }
|
||||
sed -i \
|
||||
-e "s|{{domain}}|$domain|g" \
|
||||
-e "s|{{memory_limit}}|$memory_limit|g" \
|
||||
-e "s|{{max_execution_time}}|$max_execution_time|g" \
|
||||
-e "s|{{post_max_size}}|$post_max_size|g" \
|
||||
-e "s|{{upload_max_filesize}}|$upload_max_filesize|g" \
|
||||
-- "$vHostFile" || { appError "Template substitution failed: $vHostFile"; return 1; }
|
||||
fi
|
||||
else
|
||||
openlitespeedConfigEditDelMasked 'listener\h+HTTP' map "$domain *" || return 1
|
||||
rm -f -- "$vHostFile"
|
||||
rm -f -- "$openlitespeedVhostsPath/$domain.conf0"
|
||||
rm -f -- "$openlitespeedVhostsPath/$domain.txt"
|
||||
openlitespeedConfigEdit vhost_up "$domain"
|
||||
fi
|
||||
|
||||
openlitespeedConfigNormalize "$openlitespeedConfigFile" || return 1
|
||||
}
|
||||
|
||||
# Sets a value in the OLS WebAdmin config.
|
||||
function openlitespeedAdminConfigKeySet() {
|
||||
openlitespeedAdminConfigEdit key_set "$@"
|
||||
# Sets the domain aliases for a virtual host, updating both site config and OLS listener map.
|
||||
# $1 (domain): primary site domain name.
|
||||
# $@ (...): alias domain names to assign.
|
||||
function openlitespeedAliasSet() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
shift
|
||||
|
||||
local -a aliasesRaw=("$@")
|
||||
local -a aliases=()
|
||||
|
||||
run vhostList error openlitespeedVhostList || { appError "Failed get list of virtual hosts: $error"; return 1; }
|
||||
listContains "$domain" "$vhostList" || { appError "Domain is not exists in OpenLiteSpeed config"; return 1; }
|
||||
|
||||
for aliasRaw in "${aliasesRaw[@]}"; do
|
||||
alias="$(domainPrepare "$aliasRaw")"
|
||||
[[ -n "$alias" ]] || continue
|
||||
[[ "$alias" == "$domain" ]] && continue
|
||||
arrayContains "$alias" "${aliases[@]}" || aliases+=("$alias")
|
||||
done
|
||||
|
||||
for alias in "${aliases[@]}"; do
|
||||
runError error domainCheck "$alias" || { appError "$alias: $error"; return 1; }
|
||||
listContains "$alias" "$vhostList" && { appError "$alias: Is already exists as virtual host"; return 1; }
|
||||
done
|
||||
|
||||
local aliasValue=''
|
||||
[[ ${#aliases[@]} -gt 0 ]] && aliasValue="$(IFS=','; printf '%s\n' "${aliases[*]}")"
|
||||
|
||||
local domainConfigFile="$appDataPath/config/$domain.config"
|
||||
configSet "$domainConfigFile" alias "$aliasValue" || { appError "Failed set alias in $domainConfigFile"; return 1; }
|
||||
|
||||
fileBackup "$openlitespeedConfigFile" || return 1
|
||||
openlitespeedConfigEditDelMasked 'listener\h+HTTP' map "$domain *" || return 1
|
||||
openlitespeedConfigEditAdd 'listener\h+HTTP' map "$domain $domain" || return 1
|
||||
for alias in "${aliases[@]}"; do
|
||||
openlitespeedConfigEditAdd 'listener\h+HTTP' map "$domain $alias" || return 1
|
||||
done
|
||||
|
||||
printf '%s' "$aliasValue"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Updates the Traefik middleware IP whitelist for the OLS admin panel from $olsAdminWhiteList.
|
||||
# Marks a virtual host as suspended.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedVHostDown() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local vhostList error
|
||||
run vhostList error openlitespeedVhostList || return 1
|
||||
runSilent fileCheckLineLength "$openlitespeedConfigFile" 8000 || { appError "fileCheckLineLength 8000"; return 1; }
|
||||
if listContains "$domain" "$vhostList"; then
|
||||
openlitespeedConfigEdit vhost_down "$domain" || return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Marks a virtual host as active.
|
||||
# $1 (domain): site domain name.
|
||||
function openlitespeedVHostUp() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local vhostList error
|
||||
run vhostList error openlitespeedVhostList || return 1
|
||||
|
||||
if listContains "$domain" "$vhostList"; then
|
||||
openlitespeedConfigEdit vhost_up "$domain" || return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Updates the Traefik middleware IP whitelist for the OLS admin panel from $openlitespeedAdminWhiteList.
|
||||
function openlitespeedAdminWhiteList() {
|
||||
local ipList=() whiteList error
|
||||
for i in "${!olsAdminWhiteList[@]}"; do
|
||||
ipList[$i]="\"${olsAdminWhiteList[$i]}\""
|
||||
for i in "${!openlitespeedAdminWhiteList[@]}"; do
|
||||
ipList[$i]="\"${openlitespeedAdminWhiteList[$i]}\""
|
||||
done
|
||||
whiteList=$(IFS=','; printf '%s' "${ipList[*]}")
|
||||
|
||||
runError error k3sRun patch middleware "$olsKube-admin-allowlist" --type=merge -p "{\"spec\":{\"ipWhiteList\":{\"sourceRange\":[${whiteList}]}}}" \
|
||||
runError error k3sRun patch middleware "$openlitespeedKube-admin-allowlist" --type=merge -p "{\"spec\":{\"ipWhiteList\":{\"sourceRange\":[${whiteList}]}}}" \
|
||||
|| { appError "$error"; return 1; }
|
||||
|
||||
printf '%s' "$whiteList"
|
||||
@@ -576,30 +518,9 @@ function openlitespeedAdminAllowList() {
|
||||
local allowList
|
||||
allowList=$(IFS=','; printf '%s' "${ipList[*]}")
|
||||
|
||||
fileBackup "$olsAdminPath/admin_config.conf" || return 1
|
||||
openlitespeedAdminConfigKeySet 'accessControl' 'deny' 'ALL' || return 1
|
||||
openlitespeedAdminConfigKeySet 'accessControl' 'allow' "$allowList" || return 1
|
||||
fileBackup "$openlitespeedAdminPath/admin_config.conf" || return 1
|
||||
openlitespeedAdminConfigEditSet 'accessControl' deny 'ALL' || return 1
|
||||
openlitespeedAdminConfigEditSet 'accessControl' allow "$allowList" || return 1
|
||||
|
||||
printf '%s' "$allowList"
|
||||
}
|
||||
|
||||
# Checks whether user quota support is ready on the virtual host filesystem.
|
||||
function openlitespeedQuotaCheck() {
|
||||
local quotaMount
|
||||
quotaMount=$(findmnt -no TARGET --target "$olsVhostsPath")
|
||||
[[ -n "$quotaMount" ]] || { appError "Quota mount not found: $olsVhostsPath"; return 1; }
|
||||
|
||||
local quotaOptions
|
||||
quotaOptions=$(findmnt -no OPTIONS --target "$quotaMount")
|
||||
[[ "$quotaOptions" == *usrquota* || "$quotaOptions" == *uquota* ]] || {
|
||||
appError "User quota is not enabled: mount=$quotaMount options=$quotaOptions"
|
||||
return 1
|
||||
}
|
||||
|
||||
quotaon -p "$quotaMount" 2>/dev/null | grep -qi "user quota on" || {
|
||||
appError "User quota is not active: mount=$quotaMount"
|
||||
return 1
|
||||
}
|
||||
|
||||
command -v setquota >/dev/null 2>&1 || { appError "setquota command not found"; return 1; }
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ function postfixExec() {
|
||||
function postfixPodExec() {
|
||||
local pod="$1"
|
||||
[[ -n "$pod" ]] || { appError "Pod not specified"; return 1; }
|
||||
shift || true
|
||||
shift
|
||||
|
||||
k3sRun exec pod/"$pod" -c "$postfixKube" -- "$@"
|
||||
}
|
||||
@@ -24,38 +24,340 @@ function postfixReload() {
|
||||
postfixExec postfix reload
|
||||
}
|
||||
|
||||
# Creates or updates a Postfix SASL user.
|
||||
# $1 (login): SASL username.
|
||||
# $2 (password): password.
|
||||
function postfixUserSet() {
|
||||
local login="$1" password="$2"
|
||||
[[ -n "$login" ]] || { appError "Login not specified"; return 1; }
|
||||
[[ -n "$password" ]] || { appError "Password not specified"; return 1; }
|
||||
# Rebuilds lmdb maps for domains, aliases, and senders.
|
||||
function postfixPostmapRebuild() {
|
||||
touch "$postfixConfigPath/$postfixDomainsFile" || return 1
|
||||
touch "$postfixConfigPath/$postfixAliasesFile" || return 1
|
||||
touch "$postfixConfigPath/$postfixSendersFile" || return 1
|
||||
|
||||
local error
|
||||
runError error postfixExec \
|
||||
env SASL_LOGIN="$login" SASL_PWD="$password" SASL_DB="/config/sasldb2" SASL_REALM="$postfixDefaultRealm" \
|
||||
sh -lc 'printf "%s\n" "$SASL_PWD" | saslpasswd2 -p -c -f "$SASL_DB" -u "$SASL_REALM" "$SASL_LOGIN"' || {
|
||||
appError "Failed to create/update SASL user $login: $error"
|
||||
return 1
|
||||
}
|
||||
runError error postfixExec postmap "lmdb:/config/$postfixDomainsFile" || { appError "Failed rebuild $postfixDomainsFile: $error"; return 1; }
|
||||
runError error postfixExec postmap "lmdb:/config/$postfixAliasesFile" || { appError "Failed rebuild $postfixAliasesFile: $error"; return 1; }
|
||||
runError error postfixExec postmap "lmdb:/config/$postfixSendersFile" || { appError "Failed rebuild $postfixSendersFile: $error"; return 1; }
|
||||
}
|
||||
|
||||
# Deletes a Postfix SASL user.
|
||||
# Sets or removes a key/value in a postfix map file.
|
||||
# $1 (file): path to the map file.
|
||||
# $2 (key): map key.
|
||||
# [$3] (value): map value; omit to delete the key.
|
||||
function postfixConfigSet() {
|
||||
local file="$1" key="$2" value="$3"
|
||||
[[ -n "$file" ]] || { appError "File not specified"; return 1; }
|
||||
[[ -n "$key" ]] || { appError "Key not specified"; return 1; }
|
||||
|
||||
value="${value//$'\r'/ }"
|
||||
value="${value//$'\n'/ }"
|
||||
local output error
|
||||
|
||||
if [[ ! -f "$file" ]]; then
|
||||
mkdir -p "$(dirname -- "$file")" || { appError "Failed to create folder"; return 1; }
|
||||
install -o root -g root -m 644 /dev/null "$file" || { appError "Failed to create file"; return 1; }
|
||||
else
|
||||
runError error sed -i -E "/^[[:space:]]*${key}[[:space:]]+/d" "$file" || { appError "Error writing to a file: $error"; return 1; }
|
||||
fi
|
||||
|
||||
if [[ -n "$value" ]]; then
|
||||
runShell output error printf "%s\n" "$key $value" ">>" "$file" || { appError "Error writing to a file: $error"; return 1; }
|
||||
fi
|
||||
}
|
||||
|
||||
# Sets or removes a domain entry in the virtual domains map.
|
||||
# $1 (domain): site domain name.
|
||||
# [$2] (value): map value; omit to delete.
|
||||
function postfixVirtualDomainSet() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
postfixConfigSet "$postfixConfigPath/$postfixDomainsFile" "$domain" "$2"
|
||||
}
|
||||
|
||||
# Sets or removes an entry in the virtual aliases map.
|
||||
function postfixVirtualAliasSet() {
|
||||
postfixConfigSet "$postfixConfigPath/$postfixAliasesFile" "$@"
|
||||
}
|
||||
|
||||
# Sets or removes a domain entry in the virtual domains map (lmdb-safe variant).
|
||||
# $1 (key): map key.
|
||||
# [$2] (value): map value; omit to delete.
|
||||
function postfixVirtualDomainSet2() {
|
||||
local key="$1"
|
||||
[[ -n "$key" ]] || { appError "Key not specified"; return 1; }
|
||||
local value="$2"
|
||||
local file="$postfixConfigPath/$postfixDomainsFile"
|
||||
|
||||
local escaped
|
||||
escaped=$(printf '%s\n' "$key" | sed 's/[.[\*^$()+?{}|\\/]/\\&/g')
|
||||
sed -i "/^${escaped}[[:space:]]/d" "$file" || { appError "Failed to clean old key in $file"; return 1; }
|
||||
|
||||
if [[ -n "$value" ]]; then
|
||||
printf '%s %s\n' "$key" "$value" >> "$file" || { appError "Failed to append to $file"; return 1; }
|
||||
fi
|
||||
}
|
||||
|
||||
# Adds or removes a (sender, login) pair from the owners file and rebuilds senders map.
|
||||
# $1 (sender): sender address.
|
||||
# $2 (login): SASL login.
|
||||
# [$3] (save): non-empty to add; omit to remove.
|
||||
function postfixSenderOwnerSet() {
|
||||
local sender="$1" login="$2" save="$3"
|
||||
[[ -n "$sender" ]] || { appError "Sender not set"; return 1; }
|
||||
[[ -n "$login" ]] || { appError "Login not set"; return 1; }
|
||||
local ownersFile="$postfixConfigPath/$postfixSendersFile.owners"
|
||||
touch "$ownersFile" || return 1
|
||||
|
||||
local tmp
|
||||
tmp=$(mktemp)
|
||||
awk -v s="$sender" -v l="$login" '!(NF>=2 && $1==s && $2==l)' "$ownersFile" >"$tmp"
|
||||
if [[ -n "$save" ]]; then
|
||||
printf '%s %s\n' "$sender" "$login" >>"$tmp"
|
||||
fi
|
||||
mv -f "$tmp" "$ownersFile"
|
||||
|
||||
postfixSendersRebuild
|
||||
}
|
||||
|
||||
# Sets or removes an entry in the virtual aliases map (lmdb-safe variant).
|
||||
# $1 (key): map key.
|
||||
# [$2] (value): map value; omit to delete.
|
||||
function postfixVirtualAliasSet2() {
|
||||
local key="$1"
|
||||
[[ -n "$key" ]] || { appError "Key not specified"; return 1; }
|
||||
local value="$2"
|
||||
local file="$postfixConfigPath/$postfixAliasesFile"
|
||||
|
||||
local escaped
|
||||
escaped=$(printf '%s\n' "$key" | sed 's/[.[\*^$()+?{}|\\/]/\\&/g')
|
||||
sed -i "/^${escaped}[[:space:]]/d" "$file" || { appError "Failed to clean old key in $file"; return 1; }
|
||||
|
||||
if [[ -n "$value" ]]; then
|
||||
printf '%s %s\n' "$key" "$value" >> "$file" || { appError "Failed to append to $file"; return 1; }
|
||||
fi
|
||||
}
|
||||
|
||||
# Rebuilds the senders map from the .owners file, deduplicating per sender.
|
||||
function postfixSendersRebuild() {
|
||||
local ownersFile="$postfixConfigPath/$postfixSendersFile.owners"
|
||||
local outFile="$postfixConfigPath/$postfixSendersFile"
|
||||
|
||||
touch "$ownersFile" || return 1
|
||||
|
||||
local tmpNorm tmpOut
|
||||
tmpNorm=$(mktemp)
|
||||
tmpOut=$(mktemp)
|
||||
|
||||
awk 'NF>=2 && $1 !~ /^#/ { print $1, $2 }' "$ownersFile" >"$tmpNorm"
|
||||
|
||||
awk '
|
||||
{ s=$1; o=$2; k=s SUBSEP o;
|
||||
if (!seen[k]++) {
|
||||
if (list[s]=="") list[s]=o; else list[s]=list[s] "," o;
|
||||
if (!sseen[s]++) order[++n]=s;
|
||||
}
|
||||
}
|
||||
END { for (i=1; i<=n; i++) { s=order[i]; print s " " list[s]; } }
|
||||
' "$tmpNorm" >"$tmpOut"
|
||||
|
||||
mv -f "$tmpOut" "$outFile"
|
||||
rm -f "$tmpNorm" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Creates, updates, or deletes a Postfix SASL user.
|
||||
# $1 (login): SASL username.
|
||||
function postfixUserRemove() {
|
||||
local login="$1"
|
||||
# [$2] (password): password; omit to delete the user.
|
||||
function postfixSaslUserSet() {
|
||||
local login="$1" password="$2"
|
||||
[[ -n "$login" ]] || { appError "Login not specified"; return 1; }
|
||||
|
||||
local error
|
||||
runError error postfixExec saslpasswd2 -d -f "/config/sasldb2" -u "$postfixDefaultRealm" "$login" || {
|
||||
appError "Failed to delete SASL user $login"
|
||||
if [[ -z "$password" ]]; then
|
||||
runError error postfixExec saslpasswd2 -d -f "/config/sasldb2" -u "$postfixDefaultRealm" "$login" || {
|
||||
appError "Failed to delete SASL user $login"
|
||||
return 1
|
||||
}
|
||||
else
|
||||
runError error postfixExec \
|
||||
env SASL_LOGIN="$login" SASL_PWD="$password" SASL_DB="/config/sasldb2" SASL_REALM="$postfixDefaultRealm" \
|
||||
sh -lc 'printf "%s\n" "$SASL_PWD" | saslpasswd2 -p -c -f "$SASL_DB" -u "$SASL_REALM" "$SASL_LOGIN"' || {
|
||||
appError "Failed to create/update SASL user $login: $error"
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
}
|
||||
|
||||
# Lists all domains from the virtual domains map file.
|
||||
function postfixDomainList() {
|
||||
local file="$postfixConfigPath/$postfixDomainsFile"
|
||||
[[ -f "$file" ]] || { appError "Domains file not found: $file"; return 1; }
|
||||
|
||||
awk '
|
||||
/^[[:space:]]*$/ { next }
|
||||
/^[[:space:]]*#/ { next }
|
||||
{ print $1 }
|
||||
' "$file" | sort -u
|
||||
}
|
||||
|
||||
# Registers a domain in Postfix: creates SASL user, sets sender ownership, optionally adds alias.
|
||||
# $1 (domain): site domain name.
|
||||
function postfixDomainAdd() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
local pfxId
|
||||
pfxId=$(postfixDomain2id "$domain")
|
||||
local postfixUser postfixPass
|
||||
postfixUser=$(siteConfigGetOrSet "$domain" "postfixUser" "$pfxId")
|
||||
postfixPass=$(siteConfigGetOrCreate "$domain" "postfixPass")
|
||||
|
||||
postfixSenderOwnerSet "$postfixPostmaster" "$postfixUser@$postfixDefaultRealm" "SAVE" || return 1
|
||||
postfixSaslUserSet "$postfixUser" "$postfixPass" || return 1
|
||||
|
||||
local postfixForwardTo
|
||||
postfixForwardTo=$(siteConfigGet "$domain" "postfixForwardTo")
|
||||
if [[ -n "$postfixForwardTo" ]]; then
|
||||
postfixVirtualAliasSet "@$domain" "$postfixForwardTo"
|
||||
postfixVirtualDomainSet "$domain" "OK" || return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Removes a domain from Postfix: clears SASL user, sender ownership, alias, and domain entry.
|
||||
# $1 (domain): site domain name.
|
||||
function postfixDomainRemove() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
local postfixUser
|
||||
postfixUser=$(siteConfigGet "$domain" "postfixUser")
|
||||
[[ -n "$postfixUser" ]] || { appError "postfixUser not found"; return 1; }
|
||||
|
||||
postfixVirtualDomainSet "$domain"
|
||||
postfixSenderOwnerSet "$postfixPostmaster" "$postfixUser@$postfixDefaultRealm"
|
||||
postfixSaslUserSet "$postfixUser"
|
||||
postfixVirtualAliasSet "@$domain"
|
||||
}
|
||||
|
||||
# Registers a domain in Postfix and rebuilds lmdb maps.
|
||||
# $1 (domain): site domain name.
|
||||
function postfixConfigRebuild() {
|
||||
local domain error
|
||||
domain=$(domainPrepare "$1")
|
||||
runError error domainCheck "$domain" || { appError "$error"; return 1; }
|
||||
runError error postfixDomainAdd "$domain" || { appError "$error"; return 1; }
|
||||
postfixPostmapRebuild
|
||||
}
|
||||
|
||||
# Reloads the opendkim daemon.
|
||||
function postfixDkimReload() {
|
||||
postfixExec sh -lc "pkill -HUP -f '/usr/sbin/opendkim' 2>/dev/null"
|
||||
}
|
||||
|
||||
# Lists domains that have DKIM key material present.
|
||||
function postfixDkimList() {
|
||||
ls -1 "$postfixDkimPath"/keys/*.txt 2>/dev/null | xargs -n1 basename | sed "s/\.txt$//" || true
|
||||
}
|
||||
|
||||
# Generates a DKIM keypair for a domain and updates SigningTable/KeyTable.
|
||||
# $1 (domain): domain name.
|
||||
function postfixDkimAdd() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
if ! test -s "$postfixDkimPath/keys/$domain.private" || ! test -s "$postfixDkimPath/keys/$domain.txt"; then
|
||||
postfixExec sh -lc "
|
||||
set -e
|
||||
|
||||
mkdir -p /etc/opendkim/keys
|
||||
touch /etc/opendkim/SigningTable /etc/opendkim/KeyTable
|
||||
|
||||
opendkim-genkey -b 2048 -r -D '/etc/opendkim/keys' -d '$domain' -s '$postfixDkimSelector'
|
||||
mv -f \"/etc/opendkim/keys/$postfixDkimSelector.private\" \"/etc/opendkim/keys/$domain.private\"
|
||||
mv -f \"/etc/opendkim/keys/$postfixDkimSelector.txt\" \"/etc/opendkim/keys/$domain.txt\"
|
||||
|
||||
chown opendkim:opendkim \"/etc/opendkim/keys/$domain.private\" \"/etc/opendkim/keys/$domain.txt\" || true
|
||||
chmod 0600 \"/etc/opendkim/keys/$domain.private\"
|
||||
chmod 0644 \"/etc/opendkim/keys/$domain.txt\"
|
||||
" || { appError "Failed to add DKIM for $domain"; return 1; }
|
||||
fi
|
||||
|
||||
sed -i "/^\*@$domain[[:space:]]/d" "$postfixDkimPath/SigningTable"
|
||||
sed -i "/^$postfixDkimSelector\._domainkey\.$domain[[:space:]]/d" "$postfixDkimPath/KeyTable"
|
||||
|
||||
echo "*@$domain $postfixDkimSelector._domainkey.$domain" >> "$postfixDkimPath/SigningTable"
|
||||
echo "$postfixDkimSelector._domainkey.$domain $domain:$postfixDkimSelector:/etc/opendkim/keys/$domain.private" >> "$postfixDkimPath/KeyTable"
|
||||
|
||||
postfixDkimReload
|
||||
}
|
||||
|
||||
# Autocreates DKIM keys if missing and returns the TXT record, or lists available domains.
|
||||
# [$1] (domain): domain name; omit to list all domains.
|
||||
function postfixDkimGet() {
|
||||
local domain="$1"
|
||||
if [[ -z "$domain" ]]; then
|
||||
postfixDkimList
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ ! "$domain" =~ ^[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$ ]]; then
|
||||
appError "Invalid domain: $domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
postfixDkimAdd "$domain" || { appError "Failed to create DKIM for $domain"; return 1; }
|
||||
cat "$postfixDkimPath/keys/$domain.txt" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Removes DKIM key material for a domain and reloads opendkim.
|
||||
# $1 (domain): domain name.
|
||||
function postfixDkimRemove() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
sed -i "/^\*@$domain[[:space:]]/d" "$postfixDkimPath/SigningTable"
|
||||
sed -i "/^$postfixDkimSelector\._domainkey\.$domain[[:space:]]/d" "$postfixDkimPath/KeyTable"
|
||||
|
||||
postfixDkimReload
|
||||
}
|
||||
|
||||
# Sends mail through Postfix from a raw RFC822 message file.
|
||||
# $1 (mailFrom): envelope sender address.
|
||||
# $2 (msgFile): path to the RFC822 message file.
|
||||
function postfixMailSendFromFile() {
|
||||
local mailFrom="$1" msgFile="$2"
|
||||
[[ -n "$mailFrom" ]] || { appError "Mail not specified"; return 1; }
|
||||
[[ -n "$msgFile" ]] || { appError "File not specified"; return 1; }
|
||||
|
||||
local output error
|
||||
runShell output error postfixExec sh -lc "sendmail -v -oi -t -f '$mailFrom'" "<" "$msgFile" || {
|
||||
[[ -n "$error" ]] && appError "$error"
|
||||
return 1
|
||||
}
|
||||
printf '%s' "$output"
|
||||
}
|
||||
|
||||
# Lists aliases from the virtual aliases map file.
|
||||
function postfixAliasList() {
|
||||
local file="$postfixConfigPath/$postfixAliasesFile"
|
||||
[[ -f "$file" ]] || { appError "Aliases file not found: $file"; return 1; }
|
||||
|
||||
awk '
|
||||
/^[[:space:]]*$/ { next }
|
||||
/^[[:space:]]*#/ { next }
|
||||
{ print $1 " -> " $2 }
|
||||
' "$file" | sort -u
|
||||
}
|
||||
|
||||
# Lists senders from the senders owners file.
|
||||
function postfixSendersList() {
|
||||
local file="$postfixConfigPath/$postfixSendersFile.owners"
|
||||
[[ -f "$file" ]] || { appError "Senders file not found: $file"; return 1; }
|
||||
|
||||
awk '
|
||||
/^[[:space:]]*$/ { next }
|
||||
/^[[:space:]]*#/ { next }
|
||||
{ print $1 " -> " $2 }
|
||||
' "$file" | sort -u
|
||||
}
|
||||
|
||||
# Lists all SASL users from the sasldb2 database.
|
||||
function postfixUserList() {
|
||||
function postfixSaslUserList() {
|
||||
local output error
|
||||
run output error postfixExec sasldblistusers2 -f /config/sasldb2 || { appError "$error"; return 1; }
|
||||
|
||||
@@ -65,128 +367,25 @@ function postfixUserList() {
|
||||
' <<<"$output"
|
||||
}
|
||||
|
||||
# Rebuilds the senders map from the current SASL user list.
|
||||
function postfixSendersRebuild() {
|
||||
local outFile="$postfixConfigPath/$postfixSendersFile"
|
||||
# Returns the value for a key in a postfix map file; exits non-zero if not found.
|
||||
# $1 (file): path to the map file.
|
||||
# $2 (key): map key to look up.
|
||||
function postfixMapHas() {
|
||||
local file="$1" key="$2"
|
||||
[[ -n "$file" ]] || { appError "File not specified"; return 1; }
|
||||
[[ -f "$file" ]] || { appError "File not found"; return 1; }
|
||||
[[ -n "$key" ]] || { appError "Key not specified"; return 1; }
|
||||
|
||||
local saslList error
|
||||
run saslList error postfixUserList || { appError "Failed to get SASL list: $error"; return 1; }
|
||||
|
||||
local logins
|
||||
logins=$(awk 'NF' <<<"$saslList" | paste -sd ',' -)
|
||||
|
||||
local tmpOut
|
||||
tmpOut=$(mktemp)
|
||||
[[ -n "$logins" ]] && printf '%s %s\n' "$postfixPostmaster" "$logins" > "$tmpOut"
|
||||
mv -f "$tmpOut" "$outFile"
|
||||
awk -v k="$key" 'NF>=2 && $1==k {print $2; found=1} END {exit !found}' "$file"
|
||||
}
|
||||
|
||||
function postfixConfigRebuild() {
|
||||
local domain="$1"
|
||||
if [[ -n "$domain" ]]; then
|
||||
postfixDomainSet "$domain"
|
||||
fi
|
||||
# Checks whether (postmaster, login) pair exists in the senders owners file.
|
||||
# $1 (login): SASL login to look up.
|
||||
function postfixSenderOwnerHas() {
|
||||
local login="$1"
|
||||
[[ -n "$login" ]] || { appError "Login not specified"; return 1; }
|
||||
local file="$postfixConfigPath/$postfixSendersFile.owners"
|
||||
[[ -f "$file" ]] || { appError "File not found"; return 1; }
|
||||
|
||||
local error
|
||||
# runError error postfixExec postmap "lmdb:/config/$postfixDomainsFile" || { appError "Failed rebuild $postfixDomainsFile: $error"; return 1; }
|
||||
# runError error postfixExec postmap "lmdb:/config/$postfixAliasesFile" || { appError "Failed rebuild $postfixAliasesFile: $error"; return 1; }
|
||||
runError error postfixExec postmap "lmdb:/config/$postfixSendersFile" || { appError "Failed rebuild $postfixSendersFile: $error"; return 1; }
|
||||
}
|
||||
|
||||
function postfixDomainSet() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local pfxId
|
||||
pfxId=$(postfixDomain2id "$domain")
|
||||
local postfixUser postfixPass
|
||||
postfixUser=$(siteConfigGetOrSet "$domain" "postfixUser" "$pfxId")
|
||||
postfixPass=$(siteConfigGetOrCreate "$domain" "postfixPass")
|
||||
|
||||
postfixUserSet "$postfixUser" "$postfixPass" || return 1
|
||||
postfixSendersRebuild
|
||||
postfixConfigRebuild
|
||||
}
|
||||
|
||||
function postfixDomainRemove() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
local postfixUser
|
||||
postfixUser=$(siteConfigGet "$domain" "postfixUser")
|
||||
[[ -n "$postfixUser" ]] || { appError "postfixUser not found"; return 1; }
|
||||
|
||||
postfixUserRemove "$postfixUser"
|
||||
postfixSendersRebuild
|
||||
postfixConfigRebuild
|
||||
}
|
||||
|
||||
# Reloads the opendkim daemon.
|
||||
function postfixDkimReload() {
|
||||
postfixExec sh -lc "pkill -HUP -f '/usr/sbin/opendkim' 2>/dev/null" || true
|
||||
}
|
||||
|
||||
# Lists domains that have DKIM key material present.
|
||||
function postfixDkimList() {
|
||||
local f
|
||||
for f in "$postfixDkimPath/keys/"*.txt; do
|
||||
[[ -f "$f" ]] || continue
|
||||
basename -- "$f" .txt
|
||||
done
|
||||
}
|
||||
|
||||
# Generates a DKIM keypair for a domain and updates SigningTable/KeyTable.
|
||||
# $1 (domain): domain name.
|
||||
function postfixDkimAdd() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
if [[ ! -s "$postfixDkimPath/keys/$domain.private" || ! -s "$postfixDkimPath/keys/$domain.txt" ]]; then
|
||||
postfixExec sh -lc "
|
||||
set -e
|
||||
mkdir -p /etc/opendkim/keys
|
||||
opendkim-genkey -b 2048 -r -D '/etc/opendkim/keys' -d '$domain' -s '$postfixDkimSelector'
|
||||
mv -f \"/etc/opendkim/keys/$postfixDkimSelector.private\" \"/etc/opendkim/keys/$domain.private\"
|
||||
mv -f \"/etc/opendkim/keys/$postfixDkimSelector.txt\" \"/etc/opendkim/keys/$domain.txt\"
|
||||
chown opendkim:opendkim \"/etc/opendkim/keys/$domain.private\" \"/etc/opendkim/keys/$domain.txt\" || true
|
||||
chmod 0600 \"/etc/opendkim/keys/$domain.private\"
|
||||
chmod 0644 \"/etc/opendkim/keys/$domain.txt\"
|
||||
" || { appError "Failed to generate DKIM keys for $domain"; return 1; }
|
||||
fi
|
||||
|
||||
local domainEsc="${domain//./\\.}"
|
||||
local selectorEsc="${postfixDkimSelector//./\\.}"
|
||||
sed -i "/^\*@${domainEsc}[[:space:]]/d" "$postfixDkimPath/SigningTable"
|
||||
sed -i "/^${selectorEsc}\._domainkey\.${domainEsc}[[:space:]]/d" "$postfixDkimPath/KeyTable"
|
||||
|
||||
printf '*@%s %s._domainkey.%s\n' "$domain" "$postfixDkimSelector" "$domain" >> "$postfixDkimPath/SigningTable"
|
||||
printf '%s._domainkey.%s %s:%s:/etc/opendkim/keys/%s.private\n' \
|
||||
"$postfixDkimSelector" "$domain" "$domain" "$postfixDkimSelector" "$domain" >> "$postfixDkimPath/KeyTable"
|
||||
|
||||
postfixDkimReload
|
||||
}
|
||||
|
||||
# Ensures DKIM keys exist for a domain and returns the TXT record.
|
||||
# $1 (domain): domain name.
|
||||
function postfixDkimGet() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
domainCheck "$domain" || return 1
|
||||
postfixDkimAdd "$domain" || return 1
|
||||
cat "$postfixDkimPath/keys/$domain.txt" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Removes DKIM table entries for a domain and reloads opendkim.
|
||||
# $1 (domain): domain name.
|
||||
function postfixDkimRemove() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
|
||||
local domainEsc="${domain//./\\.}"
|
||||
local selectorEsc="${postfixDkimSelector//./\\.}"
|
||||
sed -i "/^\*@${domainEsc}[[:space:]]/d" "$postfixDkimPath/SigningTable"
|
||||
sed -i "/^${selectorEsc}\._domainkey\.${domainEsc}[[:space:]]/d" "$postfixDkimPath/KeyTable"
|
||||
|
||||
postfixDkimReload
|
||||
awk -v s="$postfixPostmaster" -v l="$login" 'NF>=2 && $1==s && $2==l {found=1} END{exit !found}' "$file"
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ function redisExec() {
|
||||
function redisPodExec() {
|
||||
local pod="$1"
|
||||
[[ -n "$pod" ]] || { appError "Pod not specified"; return 1; }
|
||||
shift || true
|
||||
shift
|
||||
|
||||
local container="$redisKube"
|
||||
[[ "$pod" == "$redisSentinelKube-"* ]] && container="$redisSentinelKube"
|
||||
@@ -33,7 +33,7 @@ function redisExecCli() {
|
||||
# $2+ (...): redis-cli arguments.
|
||||
function redisPodExecCli() {
|
||||
local pod="$1"
|
||||
shift || true
|
||||
shift
|
||||
|
||||
local -a cmd=(redis-cli --no-auth-warning)
|
||||
[[ -n "$redisRootPass" ]] && cmd+=(-a "$redisRootPass")
|
||||
|
||||
@@ -5,7 +5,7 @@ function siteConfigGet() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
shift || true
|
||||
shift
|
||||
|
||||
configGet "$appDataPath/config/$domain.config" "$@"
|
||||
}
|
||||
@@ -17,7 +17,7 @@ function siteConfigSet() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
shift || true
|
||||
shift
|
||||
|
||||
configSet "$appDataPath/config/$domain.config" "$@"
|
||||
}
|
||||
@@ -29,7 +29,7 @@ function siteConfigGetOrSet() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
shift || true
|
||||
shift
|
||||
|
||||
configGetOrSet "$appDataPath/config/$domain.config" "$@"
|
||||
}
|
||||
@@ -41,7 +41,7 @@ function siteConfigGetOrCreate() {
|
||||
local domain
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
shift || true
|
||||
shift
|
||||
|
||||
configGetOrCreate "$appDataPath/config/$domain.config" "$@"
|
||||
}
|
||||
@@ -65,19 +65,19 @@ function siteAdd() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
local targetPath="$olsVhostsPath/$domain"
|
||||
local targetPath="$vhostsPath/$domain"
|
||||
[[ ! -e "$targetPath" ]] || { appError "The directory or file exists: $targetPath"; return 1; }
|
||||
|
||||
# OpenLiteSpeed
|
||||
local vhostList aliasList error
|
||||
if ! run vhostList error openlitespeedConfigVhostList; then
|
||||
if ! run vhostList error openlitespeedVhostList all; then
|
||||
appError "Error retrieving vhost list: $error"
|
||||
return 1
|
||||
elif listContains "$domain" "$vhostList"; then
|
||||
appError "Domain already exists in OpenLiteSpeed config: $domain"
|
||||
return 1
|
||||
fi
|
||||
if ! run aliasList error openlitespeedConfigAliasList; then
|
||||
if ! run aliasList error openlitespeedAliasList; then
|
||||
appError "Error retrieving alias list: $error"
|
||||
return 1
|
||||
elif listContains "$domain" "$aliasList"; then
|
||||
@@ -187,7 +187,7 @@ function siteAdd() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! runError error openlitespeedVhostSet "$domain"; then
|
||||
if ! runError error openlitespeedConfigRebuild "$domain"; then
|
||||
_siteAddRollback "Failed OLS config rebuild: $error"
|
||||
return 1
|
||||
fi
|
||||
@@ -220,14 +220,14 @@ function siteAdd() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! runError error postfixDomainSet "$domain"; then
|
||||
if ! runError error postfixDomainAdd "$domain"; then
|
||||
_siteAddRollback "Failed add domain in Postfix: $error"
|
||||
return 1
|
||||
fi
|
||||
# if ! runError error postfixPostmapRebuild; then
|
||||
# _siteAddRollback "Failed postmap rebuild: $error"
|
||||
# return 1
|
||||
# fi
|
||||
if ! runError error postfixPostmapRebuild; then
|
||||
_siteAddRollback "Failed postmap rebuild: $error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf '%s' "$domain"
|
||||
}
|
||||
@@ -259,20 +259,25 @@ function siteRemove() {
|
||||
fi
|
||||
|
||||
runSilent postfixDomainRemove "$domain"
|
||||
runSilent postfixPostmapRebuild
|
||||
runSilent systemHostRemove "$domain"
|
||||
runSilent openlitespeedVhostConfigDel "$domain"
|
||||
runSilent openlitespeedConfigRebuild "$domain" delete
|
||||
runSilent openlitespeedConfigEdit vhost_up "$domain"
|
||||
|
||||
rm -f -- "$appDataPath/config/$domain.config" &>/dev/null
|
||||
[[ -n "$domain" && "$domain" != "/" ]] && rm -rf -- "$olsVhostsPath/$domain" &>/dev/null
|
||||
rm -f "$openlitespeedVhostsPath/$domain.conf" &>/dev/null
|
||||
rm -f "$openlitespeedVhostsPath/$domain.conf0" &>/dev/null
|
||||
rm -f "$openlitespeedVhostsPath/$domain.conf.txt" &>/dev/null
|
||||
rm -f "$appDataPath/config/$domain.config" &>/dev/null
|
||||
[[ -n "$domain" && "$domain" != "/" ]] && rm -rf "$vhostsPath/$domain" &>/dev/null
|
||||
|
||||
local ug
|
||||
ug=$(domainToUser "$domain")
|
||||
if [[ -n "$ug" && "$ug" != "root" ]]; then
|
||||
if id "$ug" >/dev/null 2>&1; then
|
||||
userdel "$ug" &>/dev/null
|
||||
runSilent userdel "$ug"
|
||||
fi
|
||||
if getent group "$ug" >/dev/null 2>&1; then
|
||||
groupdel "$ug" &>/dev/null
|
||||
runSilent groupdel "$ug"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -297,7 +302,7 @@ function siteCopy() {
|
||||
fi
|
||||
|
||||
local vhostList
|
||||
if ! run vhostList error openlitespeedConfigVhostList; then
|
||||
if ! run vhostList error openlitespeedVhostList all; then
|
||||
appError "Error retrieving vhost list: $error"
|
||||
return 1
|
||||
elif ! listContains "$domain" "$vhostList"; then
|
||||
@@ -309,7 +314,7 @@ function siteCopy() {
|
||||
fi
|
||||
|
||||
local aliasList
|
||||
if ! run aliasList error openlitespeedConfigAliasList; then
|
||||
if ! run aliasList error openlitespeedAliasList; then
|
||||
appError "Error retrieving alias list: $error"
|
||||
return 1
|
||||
elif listContains "$domainNew" "$aliasList"; then
|
||||
@@ -330,7 +335,7 @@ function siteCopy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! runError error siteAdd "$domainNew" "$olsVhostsPath/$domain/www" "$databaseFile"; then
|
||||
if ! runError error siteAdd "$domainNew" "$vhostsPath/$domain/www" "$databaseFile"; then
|
||||
appError "$domainNew: Create site: $error"
|
||||
return 1
|
||||
fi
|
||||
@@ -365,13 +370,11 @@ function siteRename() {
|
||||
fi
|
||||
|
||||
local aliasList
|
||||
if run aliasList error openlitespeedConfigVhostAliasList "$domain" && [[ -n "$aliasList" ]]; then
|
||||
if run aliasList error openlitespeedVhostAlias "$domain" && [[ -n "$aliasList" ]]; then
|
||||
local -a aliases
|
||||
mapfile -t aliases <<< "$aliasList"
|
||||
# openlitespeedVhostAliasSet "$domain"
|
||||
# openlitespeedVhostAliasSet "$domainNew" "${aliases[@]}"
|
||||
openlitespeedVhostSet "$domain"
|
||||
openlitespeedVhostSet "$domainNew" "${aliases[@]}"
|
||||
openlitespeedAliasSet "$domain"
|
||||
openlitespeedAliasSet "$domainNew" "${aliases[@]}"
|
||||
fi
|
||||
|
||||
runSilent siteRemove "$domain" || true
|
||||
@@ -387,7 +390,7 @@ function sitePasswordReset() {
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local error vhostList
|
||||
run vhostList error openlitespeedConfigVhostList || { appError "Failed get list of vhosts: $error"; return 1; }
|
||||
run vhostList error openlitespeedVhostList || { appError "Failed get list of virtual hosts: $error"; return 1; }
|
||||
listContains "$domain" "$vhostList" || { appError "Domain is not exists in OpenLiteSpeed config"; return 1; }
|
||||
|
||||
local result=0
|
||||
@@ -420,7 +423,7 @@ function siteAuthReset() {
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local error vhostList
|
||||
run vhostList error openlitespeedConfigVhostList || { appError "Failed get list of vhosts: $error"; return 1; }
|
||||
run vhostList error openlitespeedVhostList || { appError "Failed get list of virtual hosts: $error"; return 1; }
|
||||
listContains "$domain" "$vhostList" || { appError "Domain is not exists in OpenLiteSpeed config"; return 1; }
|
||||
|
||||
local result=0
|
||||
|
||||
@@ -196,7 +196,7 @@ function sftpAccessEnable() {
|
||||
local output error ug
|
||||
ug=$(domainToUser "$domain")
|
||||
id "$ug" >/dev/null 2>&1 || { appError "User does not exist: $ug"; return 1; }
|
||||
[[ -d "$olsVhostsPath/$domain/www" ]] || { appError "Vhost www directory does not exist: $olsVhostsPath/$domain/www"; return 1; }
|
||||
[[ -d "$vhostsPath/$domain/www" ]] || { appError "Vhost www directory does not exist: $vhostsPath/$domain/www"; return 1; }
|
||||
|
||||
if ! id -nG "$ug" | tr ' ' '\n' | grep -Fxq "$sftpAccessGroup"; then
|
||||
run output error usermod -aG "$sftpAccessGroup" "$ug" || { appError "Add user $ug to $sftpAccessGroup: $error"; return 1; }
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
function unigmaGetTxt() {
|
||||
local domain="$1"
|
||||
local raw
|
||||
|
||||
raw=$(dig +short +time=2 +tries=1 TXT "$domain.settings.wedos-int.dev" 2>/dev/null)
|
||||
[[ -n "$raw" ]] || return 1
|
||||
|
||||
printf '%s\n' "$raw" | tr -d '"' | tr '\n' ' '
|
||||
}
|
||||
|
||||
function unigmaParse() {
|
||||
local raw="$1"
|
||||
UNIGMA_PHP="" UNIGMA_MEM="" UNIGMA_EXEC=""
|
||||
|
||||
local IFS=';' pair key value
|
||||
for pair in $raw; do
|
||||
pair="$(sed 's/^[[:space:]]*//;s/[[:space:]]*$//' <<< "$pair")"
|
||||
[[ -z "$pair" || "$pair" != *"="* ]] && continue
|
||||
|
||||
key="$(sed 's/^[[:space:]]*//;s/[[:space:]]*$//' <<< "${pair%%=*}")"
|
||||
value="$(sed 's/^[[:space:]]*//;s/[[:space:]]*$//' <<< "${pair#*=}")"
|
||||
|
||||
case "$key" in
|
||||
php) UNIGMA_PHP="$value" ;;
|
||||
mem|memory_limit) UNIGMA_MEM="$value" ;;
|
||||
exec|max_execution_time) UNIGMA_EXEC="$value" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
function unigmaIniSet() {
|
||||
local domain="$1"
|
||||
local mem="$2"
|
||||
local exec="$3"
|
||||
local file content="" existing uid gid
|
||||
|
||||
[[ -n "$mem" || -n "$exec" ]] || return 0
|
||||
|
||||
uid=$(domainToUid "$domain")
|
||||
[[ -n "$uid" ]] || { appError "Cannot resolve UID for: $domain"; return 1; }
|
||||
gid=$(domainToUid "$domain")
|
||||
[[ -n "$gid" ]] || { appError "Cannot resolve GID for: $domain"; return 1; }
|
||||
|
||||
[[ -n "$mem" ]] && content+="memory_limit = ${mem}"$'\n'
|
||||
[[ -n "$exec" ]] && content+="max_execution_time = ${exec}"$'\n'
|
||||
file="$olsPrivatePath/$domain/php/01-ols-private.ini"
|
||||
|
||||
# no change
|
||||
existing="$(cat "$file" 2>/dev/null || true)"
|
||||
[[ "${content%$'\n'}" == "$existing" ]] && return 0
|
||||
|
||||
fileAtomicWrite "$file" "$content"
|
||||
chown -- "$uid:$gid" "$file" || { appError "Change owner of file: $file"; return 1; }
|
||||
return 2
|
||||
}
|
||||
|
||||
function unigmaPhpSet() {
|
||||
local domain="$1"
|
||||
local php="$2"
|
||||
local path="$olsVhostsPath/$domain/www"
|
||||
[[ -d "$path" ]] || { appError "Directory not found: $path"; return 1; }
|
||||
|
||||
local uid gid
|
||||
uid=$(domainToUid "$domain")
|
||||
[[ -n "$uid" ]] || { appError "Cannot resolve UID for: $domain"; return 1; }
|
||||
gid=$(domainToGid "$domain")
|
||||
[[ -n "$gid" ]] || { appError "Cannot resolve GID for: $domain"; return 1; }
|
||||
|
||||
if [[ -z "$php" ]]; then
|
||||
find "$path" -maxdepth 1 -type f -name '.php[1-9][0-9]' -delete
|
||||
return 0
|
||||
fi
|
||||
|
||||
local suffix="${php//./}"
|
||||
[[ "$suffix" =~ ^[1-9][0-9]$ ]] || { appError "Incorrect PHP version: $php"; return 1; }
|
||||
|
||||
# target
|
||||
local target="$path/.php$suffix"
|
||||
|
||||
# find files .phpXX
|
||||
local -a current
|
||||
mapfile -t current < <(find "$path" -maxdepth 1 -type f -name '.php[1-9][0-9]')
|
||||
if [[ ${#current[@]} -eq 0 ]]; then
|
||||
touch "$target"
|
||||
chown -- "$uid:$gid" "$target" || true
|
||||
return 0
|
||||
fi
|
||||
|
||||
# no change
|
||||
if [[ ${#current[@]} -eq 1 && "${current[0]}" == "$target" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# rename (atomic substitution)
|
||||
mv -f "${current[0]}" "$target"
|
||||
chown -- "$uid:$gid" "$target" || true
|
||||
|
||||
# remove other files .phpXX
|
||||
if [[ ${#current[@]} -gt 1 ]]; then
|
||||
local i
|
||||
for ((i = 1; i < ${#current[@]}; i++)); do
|
||||
rm -f "${current[i]}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
function unigmaUpdate() {
|
||||
local domain="$1"
|
||||
|
||||
local raw
|
||||
raw="$(unigmaGetTxt "$domain")" || return 0
|
||||
|
||||
unigmaParse "$raw"
|
||||
unigmaIniSet "$domain" "$UNIGMA_MEM" "$UNIGMA_EXEC"
|
||||
unigmaPhpSet "$domain" "$UNIGMA_PHP"
|
||||
}
|
||||
@@ -33,16 +33,16 @@ function wordpressExec() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
domain=$(domainPrepare "$domain")
|
||||
shift || true
|
||||
shift
|
||||
|
||||
openlitespeedExec wp --path="$olsPodVhostsPath/$domain/www" --allow-root --skip-plugins --skip-themes --require="$olsPodPrivatePath/$domain/bootstrap.php" --exec='error_reporting(0);define("WP_DEBUG",false);' "$@"
|
||||
openlitespeedExec wp --path=/var/www/vhosts/"$domain"/www --allow-root --skip-plugins --skip-themes --require=/var/www/data/"$domain"/bootstrap.php --exec='error_reporting(0);define("WP_DEBUG",false);' "$@"
|
||||
}
|
||||
|
||||
function wordpressSalt() {
|
||||
local domain="$1"
|
||||
[[ -n "$domain" ]] || { appError "Domain not specified"; return 1; }
|
||||
domain=$(domainPrepare "$domain")
|
||||
shift || true
|
||||
shift
|
||||
|
||||
wordpressExec "$domain" config shuffle-salts;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ function wordpressConfigUpdate() {
|
||||
|
||||
local ug bootstrapFile tmpFile
|
||||
ug=$(domainToUser "$domain")
|
||||
bootstrapFile="$olsPrivatePath/$domain/bootstrap.php"
|
||||
bootstrapFile="$openlitespeedVhostDataPath/$domain/bootstrap.php"
|
||||
tmpFile="$bootstrapFile".tmp
|
||||
|
||||
local databaseName databaseUser databasePass redisUser redisPass postfixUser postfixPass key
|
||||
@@ -91,11 +91,6 @@ function wordpressConfigUpdate() {
|
||||
[[ -n "${!key}" ]] || { appError "wordpressConfigUpdate: $key is empty"; return 1; }
|
||||
done
|
||||
|
||||
# aliases...
|
||||
local aliasList aliasFirst error
|
||||
run aliasList error openlitespeedConfigVhostAliasList "$domain"
|
||||
aliasFirst=$(awk 'NR==1' <<< "$aliasList")
|
||||
|
||||
cat > "$tmpFile" <<PHP
|
||||
<?php
|
||||
|
||||
@@ -115,13 +110,8 @@ define('SODEW_SMTP_USER', '${postfixUser}@${postfixDefaultRealm}');
|
||||
define('SODEW_SMTP_PASS', '$postfixPass');
|
||||
define('SODEW_SMTP_HOST', '$postfixHost');
|
||||
define('SODEW_SMTP_POSTMASTER', '$postfixPostmaster');
|
||||
|
||||
define('HOSTING_WP_DOMAIN', "$domain");
|
||||
PHP
|
||||
|
||||
# adding a constant for the alias — if it exists
|
||||
[[ -n "$aliasFirst" ]] && printf "define('HOSTING_WP_INTERNAL_URL', '%s');\n" "$aliasFirst" >> "$tmpFile"
|
||||
|
||||
chown -R -- "$ug:$ug" "$tmpFile" || { appError "Change owner of vhost data directory failed: $tmpFile"; return 1; }
|
||||
chmod 600 -- "$tmpFile" || { appError "Change permissions of vhost data files failed: $tmpFile"; return 1; }
|
||||
mv -f -- "$tmpFile" "$bootstrapFile" || return 1
|
||||
@@ -134,7 +124,7 @@ function wordpressConfigDefine() {
|
||||
domain=$(domainPrepare "$1")
|
||||
domainCheck "$domain" || return 1
|
||||
|
||||
local configFile="$olsVhostsPath/$domain/www/wp-config.php"
|
||||
local configFile="$vhostsPath/$domain/www/wp-config.php"
|
||||
[[ -f "$configFile" ]] || { appError "File not found: $configFile"; return 1; }
|
||||
|
||||
local constants=(
|
||||
@@ -173,7 +163,7 @@ function wordpressConfigRebuild() {
|
||||
wordpressConfigUpdate "$domain" || return 1
|
||||
|
||||
local muPluginsPath ug
|
||||
muPluginsPath="$olsVhostsPath/$domain/www/wp-content/mu-plugins"
|
||||
muPluginsPath="$vhostsPath/$domain/www/wp-content/mu-plugins"
|
||||
ug=$(domainToUser "$domain")
|
||||
|
||||
[[ -d "$muPluginsPath" ]] || mkdir -p -- "$muPluginsPath" || { appError "Create directory failed: $muPluginsPath"; return 1; }
|
||||
@@ -288,8 +278,8 @@ function wordpressDomainUpdate() {
|
||||
wordpressSearchReplace "$domain" "$rootOld" "$siteNew"
|
||||
fi
|
||||
if [[ -n "$abspathOld" ]]; then
|
||||
printInfo "$wordpressLabel Replace in DB (6): $abspathOld --> $olsPodVhostsPath/$domain/www"
|
||||
wordpressSearchReplace "$domain" "$abspathOld" "$olsPodVhostsPath/$domain/www"
|
||||
printInfo "$wordpressLabel Replace in DB (6): $abspathOld --> /var/www/vhosts/$domain/www"
|
||||
wordpressSearchReplace "$domain" "$abspathOld" "/var/www/vhosts/$domain/www"
|
||||
fi
|
||||
|
||||
printInfo "$wordpressLabel Replace in DB (7): $hostOld --> $domain"
|
||||
|
||||
Reference in New Issue
Block a user