Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d385627251 | |||
| 8df8b715c7 | |||
| b90c692af1 |
+96
-3
@@ -1182,21 +1182,114 @@ else
|
|||||||
echo_ok
|
echo_ok
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echononl "\tMake file composer.json writable.."
|
||||||
|
chown ${HTTP_USER} ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION}/composer.json > $log_file 2>&1
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
echo_ok
|
||||||
|
else
|
||||||
|
echo_failed
|
||||||
|
error "$(cat $log_file)"
|
||||||
|
|
||||||
|
echononl "\tcontinue anyway [yes/no]: "
|
||||||
|
read OK
|
||||||
|
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
|
||||||
|
echononl "Wrong entry! - repeat [yes/nno]: "
|
||||||
|
read OK
|
||||||
|
done
|
||||||
|
[[ $OK = "yes" ]] || fatal "Script terminated by user input.."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echononl "\tCreate composer.lock file.."
|
||||||
|
if [[ ${PF_ADMIN_MAJOR_VERSION} -gt 3 ]] ; then
|
||||||
|
if $PHP_DEBIAN_INSTALLATION ; then
|
||||||
|
|
||||||
|
su ${HTTP_USER} -s /bin/bash -c "cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION} && \
|
||||||
|
php /usr/local/bin/composer config --json \
|
||||||
|
policy.advisories.ignore-id '[\"PKSA-qv5y-crcz-9nxw\",\"PKSA-kbc7-dq62-pt7d\"]'" \
|
||||||
|
> $log_file 2>&1
|
||||||
|
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
su ${HTTP_USER} -s /bin/bash -c "cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION} && \
|
||||||
|
/usr/local/php-${php_latest_ver}/bin/php /usr/local/bin/composer config --json \
|
||||||
|
policy.advisories.ignore-id '[\"PKSA-qv5y-crcz-9nxw\",\"PKSA-kbc7-dq62-pt7d\"]'" \
|
||||||
|
> $log_file 2>&1
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
echo_ok
|
||||||
|
else
|
||||||
|
echo_failed
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "\tCommand was: "
|
||||||
|
if $PHP_DEBIAN_INSTALLATION ; then
|
||||||
|
cat <<EOF
|
||||||
|
su ${HTTP_USER} -s /bin/bash -c "cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION} && \
|
||||||
|
php /usr/local/bin/composer config --json \
|
||||||
|
policy.advisories.ignore-id '[\"PKSA-qv5y-crcz-9nxw\",\"PKSA-kbc7-dq62-pt7d\"]'" \
|
||||||
|
> $log_file 2>&1
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat <<EOF
|
||||||
|
su ${HTTP_USER} -s /bin/bash -c "cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION} && \
|
||||||
|
/usr/local/php-${php_latest_ver}/bin/php /usr/local/bin/composer config --json \
|
||||||
|
policy.advisories.ignore-id '[\"PKSA-qv5y-crcz-9nxw\",\"PKSA-kbc7-dq62-pt7d\"]'" \
|
||||||
|
> $log_file 2>&1
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
error "$(cat $log_file)"
|
||||||
|
|
||||||
|
echononl "\tcontinue anyway [yes/no]: "
|
||||||
|
read OK
|
||||||
|
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
|
||||||
|
echononl "Wrong entry! - repeat [yes/nno]: "
|
||||||
|
read OK
|
||||||
|
done
|
||||||
|
[[ $OK = "yes" ]] || fatal "Script terminated by user input.."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
echononl "\tInstall PHP dependencies ( composer install --no-dev ... ).."
|
echononl "\tInstall PHP dependencies ( composer install --no-dev ... ).."
|
||||||
if [[ ${PF_ADMIN_MAJOR_VERSION} -gt 3 ]] ; then
|
if [[ ${PF_ADMIN_MAJOR_VERSION} -gt 3 ]] ; then
|
||||||
if $PHP_DEBIAN_INSTALLATION ; then
|
if $PHP_DEBIAN_INSTALLATION ; then
|
||||||
su ${HTTP_USER} -c"cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION}
|
su ${HTTP_USER} -c"cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION} && \
|
||||||
php /usr/local/bin/composer install --prefer-dist --no-interaction --no-dev" -s /bin/bash \
|
php /usr/local/bin/composer install --prefer-dist --no-interaction --no-dev" -s /bin/bash \
|
||||||
> $log_file 2>&1
|
> $log_file 2>&1
|
||||||
else
|
else
|
||||||
su ${HTTP_USER} -c"cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION}
|
su ${HTTP_USER} -c"cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION} && \
|
||||||
/usr/local/php-${php_latest_ver}/bin/php /usr/local/bin/composer --prefer-dist \
|
/usr/local/php-${php_latest_ver}/bin/php /usr/local/bin/composer --prefer-dist \
|
||||||
--no-interaction install --no-dev" -s /bin/bash > $log_file 2>&1
|
--no-interaction install --no-dev" -s /bin/bash > $log_file 2>&1
|
||||||
fi
|
fi
|
||||||
if [[ $? -eq 0 ]]; then
|
if [[ $? -eq 0 ]]; then
|
||||||
echo_ok
|
echo_ok
|
||||||
else
|
else
|
||||||
echo_failed
|
echo_failed
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "\tCommand was: "
|
||||||
|
if $PHP_DEBIAN_INSTALLATION ; then
|
||||||
|
cat <<EOF
|
||||||
|
su ${HTTP_USER} -c"cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION} && \\
|
||||||
|
php /usr/local/bin/composer --prefer-dist --no-interaction install --no-dev" -s /bin/bash \\
|
||||||
|
> $log_file 2>&1
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat <<EOF
|
||||||
|
su ${HTTP_USER} -c"cd ${WEBSITE_BASEDIR}/postfixadmin-${PF_ADMIN_VERSION} && \\
|
||||||
|
/usr/local/php-${php_latest_ver}/bin/php /usr/local/bin/composer --prefer-dist \\
|
||||||
|
--no-interaction install --no-dev" -s /bin/bash > $log_file 2>&1
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
error "$(cat $log_file)"
|
error "$(cat $log_file)"
|
||||||
|
|
||||||
echononl "\tcontinue anyway [yes/no]: "
|
echononl "\tcontinue anyway [yes/no]: "
|
||||||
|
|||||||
Executable
+108
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Batch-update the quota2 table for all active mailboxes.
|
||||||
|
|
||||||
|
Uses 'doveadm quota get' (must run as root) to read current usage and
|
||||||
|
writes it to quota2 via INSERT ... ON CONFLICT DO UPDATE.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
update_quota2.sh [--dry-run] [--limit N]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--dry-run Print what would be done without touching the database.
|
||||||
|
--limit N Process only the first N mailboxes (useful for testing).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
DOVEADM = '/usr/local/dovecot/bin/doveadm'
|
||||||
|
PSQL = 'psql'
|
||||||
|
DB_USER = 'postfix'
|
||||||
|
DB_NAME = 'postfix'
|
||||||
|
|
||||||
|
|
||||||
|
def get_users(limit=None):
|
||||||
|
query = 'SELECT username FROM mailbox WHERE active = true ORDER BY username;'
|
||||||
|
if limit:
|
||||||
|
query = ('SELECT username FROM mailbox WHERE active = true '
|
||||||
|
'ORDER BY username LIMIT %d;' % limit)
|
||||||
|
result = subprocess.run(
|
||||||
|
[PSQL, '-U', DB_USER, DB_NAME, '-tAF', '|', '-c', query],
|
||||||
|
capture_output=True, text=True
|
||||||
|
)
|
||||||
|
return [u.strip() for u in result.stdout.strip().split('\n') if u.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def get_quota(user):
|
||||||
|
"""Returns (bytes, messages) or (None, None) if not available."""
|
||||||
|
result = subprocess.run(
|
||||||
|
[DOVEADM, 'quota', 'get', '-u', user],
|
||||||
|
capture_output=True, text=True
|
||||||
|
)
|
||||||
|
bytes_val = messages_val = None
|
||||||
|
for line in result.stdout.splitlines():
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) < 4:
|
||||||
|
continue
|
||||||
|
if parts[2] == 'STORAGE' and parts[1] != 'Type':
|
||||||
|
try:
|
||||||
|
bytes_val = int(parts[3]) * 1024 # KiB → bytes
|
||||||
|
except ValueError:
|
||||||
|
bytes_val = 0
|
||||||
|
elif parts[2] == 'MESSAGE' and parts[1] != 'Type':
|
||||||
|
try:
|
||||||
|
messages_val = int(parts[3])
|
||||||
|
except ValueError:
|
||||||
|
messages_val = 0
|
||||||
|
return bytes_val, messages_val
|
||||||
|
|
||||||
|
|
||||||
|
def upsert_quota2(user, bytes_val, messages_val):
|
||||||
|
sql = (
|
||||||
|
"INSERT INTO quota2 (username, bytes, messages) VALUES ('"
|
||||||
|
+ user.replace("'", "''")
|
||||||
|
+ "', " + str(bytes_val) + ", " + str(messages_val) + ") "
|
||||||
|
"ON CONFLICT (username) DO UPDATE "
|
||||||
|
"SET bytes = EXCLUDED.bytes, messages = EXCLUDED.messages;"
|
||||||
|
)
|
||||||
|
subprocess.run([PSQL, '-U', DB_USER, DB_NAME, '-c', sql],
|
||||||
|
capture_output=True)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
dry_run = '--dry-run' in sys.argv
|
||||||
|
limit = None
|
||||||
|
if '--limit' in sys.argv:
|
||||||
|
idx = sys.argv.index('--limit')
|
||||||
|
try:
|
||||||
|
limit = int(sys.argv[idx + 1])
|
||||||
|
except (IndexError, ValueError):
|
||||||
|
print('Usage: update_quota2.sh [--dry-run] [--limit N]')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
users = get_users(limit)
|
||||||
|
total = len(users)
|
||||||
|
print('Processing %d mailboxes...' % total)
|
||||||
|
|
||||||
|
updated = skipped = 0
|
||||||
|
for i, user in enumerate(users, 1):
|
||||||
|
bytes_val, messages_val = get_quota(user)
|
||||||
|
if bytes_val is None or messages_val is None:
|
||||||
|
print(' [%d/%d] SKIP %s (no quota data)' % (i, total, user))
|
||||||
|
skipped += 1
|
||||||
|
continue
|
||||||
|
if dry_run:
|
||||||
|
print(' [%d/%d] DRY %s: %d bytes, %d messages'
|
||||||
|
% (i, total, user, bytes_val, messages_val))
|
||||||
|
else:
|
||||||
|
upsert_quota2(user, bytes_val, messages_val)
|
||||||
|
if i % 50 == 0 or i == total:
|
||||||
|
print(' [%d/%d] done' % (i, total))
|
||||||
|
updated += 1
|
||||||
|
|
||||||
|
print('Done: %d updated, %d skipped.' % (updated, skipped))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user