diff --git a/README.md b/README.md index 730e314..420ce4c 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,8 @@ Connect to the new database and grant privileges required for migrations and run ```sql \c vctp +ALTER DATABASE vctp OWNER TO vctp_user; +ALTER SCHEMA public OWNER TO vctp_user; GRANT CONNECT, TEMP ON DATABASE vctp TO vctp_user; GRANT USAGE, CREATE ON SCHEMA public TO vctp_user; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO vctp_user; @@ -155,6 +157,12 @@ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO vctp_user; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO vctp_user; ``` +Verify effective schema privileges (useful if migrations fail creating `goose_db_version`): + +```sql +SELECT has_schema_privilege('vctp_user', 'public', 'USAGE,CREATE'); +``` + Recommended auth/network configuration: - Ensure PostgreSQL is listening on the expected interface/port in `postgresql.conf` (for example, `listen_addresses` and `port`). @@ -241,6 +249,9 @@ Database: HTTP/TLS: - `settings.bind_ip`: IP address to bind the HTTP server - `settings.bind_port`: TCP port to bind the HTTP server +- `settings.bind_port` below `1024` (for example `443`) requires privileged bind permissions. + The packaged systemd unit grants `CAP_NET_BIND_SERVICE` to the `vctp` user; if you run + vCTP outside that unit, grant equivalent capability or use a non-privileged port. - `settings.bind_disable_tls`: `true` to serve plain HTTP (no TLS) - `settings.tls_cert_filename`: PEM certificate path (TLS mode) - `settings.tls_key_filename`: PEM private key path (TLS mode) diff --git a/db/helpers.go b/db/helpers.go index 3b2dc74..4e8cb30 100644 --- a/db/helpers.go +++ b/db/helpers.go @@ -3096,6 +3096,21 @@ CREATE TABLE IF NOT EXISTS snapshot_runs ( return nil } +// EnsureCronStatusTable creates a table to track cron job progress/status. +func EnsureCronStatusTable(ctx context.Context, dbConn *sqlx.DB) error { + ddl := ` +CREATE TABLE IF NOT EXISTS cron_status ( + job_name TEXT PRIMARY KEY, + started_at BIGINT NOT NULL, + ended_at BIGINT NOT NULL, + duration_ms BIGINT NOT NULL, + last_error TEXT, + in_progress BOOLEAN NOT NULL DEFAULT FALSE +);` + _, err := execLog(ctx, dbConn, ddl) + return err +} + // UpsertSnapshotRun updates or inserts snapshot run status. func UpsertSnapshotRun(ctx context.Context, dbConn *sqlx.DB, vcenter string, snapshotTime time.Time, success bool, errMsg string) error { if err := EnsureSnapshotRunTable(ctx, dbConn); err != nil { diff --git a/db/sqlite_import.go b/db/sqlite_import.go index d716845..a4f6abf 100644 --- a/db/sqlite_import.go +++ b/db/sqlite_import.go @@ -164,6 +164,8 @@ func ensureDestinationImportTable(ctx context.Context, destination *sqlx.DB, tab return EnsureSummaryTable(ctx, destination, tableName) case tableName == "snapshot_runs": return EnsureSnapshotRunTable(ctx, destination) + case tableName == "cron_status": + return EnsureCronStatusTable(ctx, destination) case tableName == "vm_hourly_stats": return EnsureVmHourlyStats(ctx, destination) case tableName == "vm_lifecycle_cache": diff --git a/src/vctp.service b/src/vctp.service index d3fc691..e286782 100644 --- a/src/vctp.service +++ b/src/vctp.service @@ -15,8 +15,9 @@ Restart=always RestartSec=10s #LimitNOFILE=65536 SyslogIdentifier=vctp -#CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_FOWNER CAP_DAC_OVERRIDE CAP_SETUID CAP_SETGID CAP_SYS_RESOURCE CAP_AUDIT_WRITE -#AmbientCapabilities=CAP_NET_BIND_SERVICE +# Allow non-root service user to bind privileged ports (e.g., 443). +CapabilityBoundingSet=CAP_NET_BIND_SERVICE +AmbientCapabilities=CAP_NET_BIND_SERVICE [Install] WantedBy=multi-user.target