@@ -53,7 +53,7 @@ show_help() {
5353 echo " COMMANDS:"
5454 echo " quickstart [--demo] [--api-key=KEY] [--db-url=URL] [-y] Complete setup: install, configure, and start monitoring"
5555 echo " install [--demo] Clone repository and setup the monitoring project"
56- echo " start Start all monitoring services using Docker Compose"
56+ echo " start Start all monitoring services using Docker Compose (auto-generates secure Grafana password) "
5757 echo " stop Stop all services"
5858 echo " restart Restart all services"
5959 echo " status Show status of all services"
@@ -77,6 +77,10 @@ show_help() {
7777 echo " show-key Show current API key (masked)"
7878 echo " remove-key Remove stored API key"
7979 echo " "
80+ echo " GRAFANA PASSWORD MANAGEMENT:"
81+ echo " generate-grafana-password Generate secure password for Grafana"
82+ echo " show-grafana-credentials Show current Grafana credentials"
83+ echo " "
8084 echo " OPTIONS:"
8185 echo " --demo Include demo PostgreSQL database for testing"
8286 echo " --api-key=KEY Provide API key for automated report uploads"
@@ -99,11 +103,13 @@ show_help() {
99103 echo " $0 quickstart -y --api-key=key --db-url=postgresql://user:pass@host:5432/db # Fully automated setup"
100104 echo " $0 install # Clone repository and setup for production"
101105 echo " $0 install --demo # Clone repository and setup with demo database"
102- echo " $0 start # Start monitoring services"
106+ echo " $0 start # Start monitoring services (auto-generates secure Grafana password) "
103107 echo " $0 logs pgwatch-postgres # Show logs for postgres pgwatch instance"
104108 echo " $0 health # Check if all services are healthy"
105109 echo " $0 shell target-db # Open shell in target database (demo mode only)"
106110 echo " $0 check # Verify system prerequisites and readiness"
111+ echo " $0 generate-grafana-password # Generate secure password for Grafana"
112+ echo " $0 show-grafana-credentials # Show current Grafana login credentials"
107113 echo " "
108114 echo " INSTANCE MANAGEMENT EXAMPLES:"
109115 echo " $0 list-instances # Show all configured instances"
@@ -118,17 +124,18 @@ show_help() {
118124 echo " • Add '--api-key=your_key' to any quickstart command for automated report uploads"
119125 echo " • Add '--db-url=postgresql://user:pass@host:port/db' to automatically configure a database"
120126 echo " • Add '-y' to accept all defaults and skip interactive prompts (useful for automation)"
127+ echo " • Secure Grafana password is automatically generated for all setups"
121128 echo " "
122129 echo " MANUAL SETUP:"
123130 echo " PRODUCTION MODE:"
124131 echo " 1. Run '$0 install' to setup monitoring infrastructure"
125132 echo " 2. Add your PostgreSQL instances: '$0 add-instance postgresql://user:pass@host:port/db'"
126- echo " 3. Start monitoring: '$0 start'"
133+ echo " 3. Start monitoring: '$0 start' (auto-generates secure Grafana password) "
127134 echo " "
128135 echo " DEMO MODE:"
129136 echo " 1. Run '$0 install --demo' to setup with demo database included"
130- echo " 2. Start all services: '$0 start'"
131- echo " 3. Access demo database at localhost:5432 "
137+ echo " 2. Start all services: '$0 start' (auto-generates secure Grafana password) "
138+ echo " 3. Access demo database at localhost:55432 "
132139 echo " "
133140 echo " The CLI auto-detects the project directory and should be run from outside it"
134141 echo
@@ -146,12 +153,12 @@ show_help() {
146153 echo " 🚀 MAIN: Grafana Dashboard: http://localhost:3000 (demouser/demopwd)"
147154 echo " "
148155 echo " Technical URLs (for advanced users):"
149- echo " PGWatch Postgres: http://localhost:8080 "
150- echo " PGWatch Prometheus: http://localhost:8089 "
151- echo " Prometheus: http://localhost:9090 "
152- echo " Flask API: http://localhost:5000 "
153- echo " Sink DB: postgresql://postgres:postgres@localhost:5433 /postgres"
154- echo " Demo DB: postgresql://postgres:postgres@localhost:5432 /target_database (--demo mode only)"
156+ echo " PGWatch Postgres: http://localhost:58080 "
157+ echo " PGWatch Prometheus: http://localhost:58089 "
158+ echo " Prometheus: http://localhost:59090 "
159+ echo " Flask API: http://localhost:55000 "
160+ echo " Sink DB: postgresql://postgres:postgres@localhost:55433 /postgres"
161+ echo " Demo DB: postgresql://postgres:postgres@localhost:55432 /target_database (--demo mode only)"
155162}
156163
157164# Check basic prerequisites (software installation)
@@ -243,7 +250,7 @@ check_system_resources() {
243250 fi
244251
245252 # Check if required ports are available
246- local required_ports=(3000 5000 5432 5433 8080 8089 9090 )
253+ local required_ports=(3000 55000 55432 55433 58080 58089 59090 )
247254 local ports_in_use=()
248255
249256 for port in " ${required_ports[@]} " ; do
@@ -261,8 +268,8 @@ check_system_resources() {
261268 if [ ${# ports_in_use[@]} -ne 0 ]; then
262269 log_warning " The following ports are already in use: ${ports_in_use[*]} "
263270 log_warning " This may cause conflicts when starting services"
264- echo " Required ports: 3000 (Grafana), 5000 (Flask), 5432 (Target DB), 5433 (Sink DB),"
265- echo " 8080 (PGWatch), 8089 (PGWatch Prometheus), 9090 (Prometheus)"
271+ echo " Required ports: 3000 (Grafana), 55000 (Flask), 55432 (Target DB), 55433 (Sink DB),"
272+ echo " 58080 (PGWatch), 58089 (PGWatch Prometheus), 59090 (Prometheus)"
266273 fi
267274
268275 log_success " System resources check completed"
@@ -471,6 +478,146 @@ is_demo_mode() {
471478 return 1
472479}
473480
481+ # Password Generator Functions
482+
483+ # Generate a secure random password
484+ generate_secure_password () {
485+ # Generate a 16-character password with mixed case, numbers, and special characters
486+ local password
487+ password=$( openssl rand -base64 12 | tr -d " =+/" | cut -c1-16)
488+
489+ # Ensure it contains at least one uppercase, one lowercase, one number, and one special character
490+ local upper=$( echo {A..Z} | tr -d ' ' | fold -w1 | sort -R | head -1)
491+ local lower=$( echo {a..z} | tr -d ' ' | fold -w1 | sort -R | head -1)
492+ local number=$( echo {0..9} | tr -d ' ' | fold -w1 | sort -R | head -1)
493+ local special=$( echo " !@#$%^&*" | fold -w1 | sort -R | head -1)
494+
495+ # Replace characters at random positions
496+ local pos1=$(( RANDOM % 16 ))
497+ local pos2=$(( RANDOM % 16 ))
498+ local pos3=$(( RANDOM % 16 ))
499+ local pos4=$(( RANDOM % 16 ))
500+
501+ # Ensure all positions are different
502+ while [ " $pos2 " -eq " $pos1 " ]; do pos2=$(( RANDOM % 16 )) ; done
503+ while [ " $pos3 " -eq " $pos1 " ] || [ " $pos3 " -eq " $pos2 " ]; do pos3=$(( RANDOM % 16 )) ; done
504+ while [ " $pos4 " -eq " $pos1 " ] || [ " $pos4 " -eq " $pos2 " ] || [ " $pos4 " -eq " $pos3 " ]; do pos4=$(( RANDOM % 16 )) ; done
505+
506+ # Build the final password
507+ password=$( echo " $password " | sed " s/./$upper /$(( pos1 + 1 )) " | sed " s/./$lower /$(( pos2 + 1 )) " | sed " s/./$number /$(( pos3 + 1 )) " | sed " s/./$special /$(( pos4 + 1 )) " )
508+
509+ echo " $password "
510+ }
511+
512+ # Check if Grafana password exists
513+ check_grafana_password_exists () {
514+ if [ -f " $SCRIPT_DIR /.pgwatch-config" ]; then
515+ local password=$( grep " ^grafana_password=" " $SCRIPT_DIR /.pgwatch-config" 2> /dev/null | cut -d' =' -f2)
516+ if [ -n " $password " ]; then
517+ return 0 # Password exists
518+ fi
519+ fi
520+ return 1 # Password doesn't exist
521+ }
522+
523+ # Ensure Grafana password exists (generate if needed)
524+ ensure_grafana_password () {
525+ if ! check_grafana_password_exists; then
526+ log_info " No Grafana password configured - generating secure password..."
527+ generate_grafana_password
528+ else
529+ log_info " Grafana password already configured"
530+ fi
531+ }
532+
533+ # Generate Grafana password and update configuration
534+ generate_grafana_password () {
535+ local password
536+ password=$( generate_secure_password)
537+
538+ # Create config file if it doesn't exist
539+ touch " $SCRIPT_DIR /.pgwatch-config"
540+
541+ # Remove existing grafana_password line if present
542+ if [ -f " $SCRIPT_DIR /.pgwatch-config" ]; then
543+ grep -v " ^grafana_password=" " $SCRIPT_DIR /.pgwatch-config" > " $SCRIPT_DIR /.pgwatch-config.tmp" || true
544+ mv " $SCRIPT_DIR /.pgwatch-config.tmp" " $SCRIPT_DIR /.pgwatch-config"
545+ fi
546+
547+ # Add the new Grafana password
548+ echo " grafana_password=$password " >> " $SCRIPT_DIR /.pgwatch-config"
549+
550+ log_success " Grafana password generated successfully"
551+ log_info " New password: $password "
552+ log_info " Username: monitor"
553+ log_info " Access Grafana at: http://localhost:3000"
554+
555+ # Change password via existing Grafana container
556+ change_grafana_password_via_container " $password "
557+
558+ return 0
559+ }
560+
561+ # Change Grafana password via existing container
562+ change_grafana_password_via_container () {
563+ local password=" $1 "
564+ local compose_cmd=$( get_compose_cmd)
565+
566+ cd " $SCRIPT_DIR "
567+
568+ # Check if Grafana container is running
569+ if ! $compose_cmd -f " $COMPOSE_FILE " ps --services --filter " status=running" | grep -q " grafana" ; then
570+ log_warning " Grafana container is not running. Starting it first..."
571+ $compose_cmd -f " $COMPOSE_FILE " up -d grafana
572+
573+ # Wait for Grafana to be ready
574+ log_info " Waiting for Grafana to be ready..."
575+ sleep 10
576+ fi
577+
578+ # Change password using Grafana CLI inside the container
579+ log_info " Changing Grafana password via container..."
580+
581+ # Use grafana-cli to change the admin password
582+ if $compose_cmd -f " $COMPOSE_FILE " exec -T grafana grafana-cli admin reset-admin-password " $password " > /dev/null 2>&1 ; then
583+ log_success " Grafana password changed successfully via container"
584+ else
585+ log_warning " Failed to change password via grafana-cli, trying alternative method..."
586+
587+ # Alternative: Use SQL to update password directly in database
588+ if $compose_cmd -f " $COMPOSE_FILE " exec -T grafana sqlite3 /var/lib/grafana/grafana.db " UPDATE user SET password = '$password ' WHERE login = 'monitor';" > /dev/null 2>&1 ; then
589+ log_success " Grafana password changed successfully via database update"
590+ else
591+ log_error " Failed to change Grafana password via container"
592+ log_info " Password has been saved to .pgwatch-config but may need manual update in Grafana"
593+ return 1
594+ fi
595+ fi
596+
597+ log_info " Password saved to .pgwatch-config file"
598+ }
599+
600+ # Show current Grafana credentials
601+ show_grafana_credentials () {
602+ if [ -f " $SCRIPT_DIR /.pgwatch-config" ]; then
603+ local password=$( grep " ^grafana_password=" " $SCRIPT_DIR /.pgwatch-config" 2> /dev/null | cut -d' =' -f2)
604+ if [ -n " $password " ]; then
605+ log_info " Current Grafana credentials:"
606+ echo " Username: monitor"
607+ echo " Password: $password "
608+ echo " URL: http://localhost:3000"
609+ else
610+ log_warning " No custom Grafana password configured"
611+ log_info " Using default credentials: monitor/demo"
612+ log_info " Use '$0 generate-grafana-password' to set a secure password"
613+ fi
614+ else
615+ log_warning " No Grafana password configured"
616+ log_info " Using default credentials: monitor/demo"
617+ log_info " Use '$0 generate-grafana-password' to set a secure password"
618+ fi
619+ }
620+
474621# API Key Management Functions
475622
476623# Add API key to configuration
653800
654801 if [ " $demo_mode " = true ]; then
655802 log_info " You can now start all services (including demo database) with: $0 start"
656- log_info " The demo database will be available at: postgresql://postgres:postgres@localhost:5432 /target_database"
803+ log_info " The demo database will be available at: postgresql://postgres:postgres@localhost:55432 /target_database"
657804 else
658805 log_info " You can now:"
659806 echo " 1. Add PostgreSQL instances to monitor: $0 add-instance 'postgresql://user:pass@host:port/db'"
@@ -872,16 +1019,25 @@ quickstart_setup() {
8721019 fi
8731020 update_config
8741021
875- # Step 5/4: Start services
1022+ # Step 5/4: Ensure Grafana password is configured
8761023 echo
8771024 if [ " $demo_mode " = true ]; then
878- log_info " Step 4: Starting monitoring services ..."
1025+ log_info " Step 4: Configuring Grafana security ..."
8791026 else
1027+ log_info " Step 5: Configuring Grafana security..."
1028+ fi
1029+ ensure_grafana_password
1030+
1031+ # Step 6/5: Start services
1032+ echo
1033+ if [ " $demo_mode " = true ]; then
8801034 log_info " Step 5: Starting monitoring services..."
1035+ else
1036+ log_info " Step 6: Starting monitoring services..."
8811037 fi
8821038 start_services
8831039
884- # Step 6/5 : Final summary
1040+ # Step 7/6 : Final summary
8851041 echo
8861042 log_success " 🎉 Quickstart setup completed successfully!"
8871043 echo
@@ -890,7 +1046,7 @@ quickstart_setup() {
8901046 echo " ✅ Demo PostgreSQL database (monitoring target)"
8911047 fi
8921048 echo " ✅ PostgreSQL monitoring infrastructure"
893- echo " ✅ Grafana dashboards"
1049+ echo " ✅ Grafana dashboards (with secure password) "
8941050 echo " ✅ Prometheus metrics storage"
8951051 echo " ✅ Flask API backend"
8961052 echo " ✅ Automated report generation (every 24h)"
@@ -904,7 +1060,7 @@ quickstart_setup() {
9041060 else
9051061 log_info " Demo mode next steps:"
9061062 echo " • Explore Grafana dashboards at http://localhost:3000"
907- echo " • Connect to demo database: postgresql://postgres:postgres@localhost:5432 /target_database"
1063+ echo " • Connect to demo database: postgresql://postgres:postgres@localhost:55432 /target_database"
9081064 echo " • Generate some load on the demo database to see metrics"
9091065 fi
9101066
@@ -925,6 +1081,9 @@ get_compose_cmd() {
9251081start_services () {
9261082 precheck_for_services
9271083
1084+ # Ensure Grafana password is configured before starting services
1085+ ensure_grafana_password
1086+
9281087 local compose_cmd=$( get_compose_cmd)
9291088
9301089 cd " $SCRIPT_DIR "
@@ -1002,17 +1161,17 @@ health_check() {
10021161 log_info " Performing health checks..."
10031162
10041163 local services=(
1005- " sink-postgres:5433 :PostgreSQL Sink"
1006- " pgwatch-postgres:8080 :PGWatch PostgreSQL"
1007- " pgwatch-prometheus:8089 :PGWatch Prometheus"
1008- " sink-prometheus:9090 :Prometheus"
1164+ " sink-postgres:55433 :PostgreSQL Sink"
1165+ " pgwatch-postgres:58080 :PGWatch PostgreSQL"
1166+ " pgwatch-prometheus:58089 :PGWatch Prometheus"
1167+ " sink-prometheus:59090 :Prometheus"
10091168 " grafana:3000:Grafana"
1010- " flask-pgss-api:5000 :Flask API"
1169+ " flask-pgss-api:55000 :Flask API"
10111170 )
10121171
10131172 # Add target-db only in demo mode
10141173 if is_demo_mode; then
1015- services=(" target-db:5432 :PostgreSQL Target Database" " ${services[@]} " )
1174+ services=(" target-db:55432 :PostgreSQL Target Database" " ${services[@]} " )
10161175 fi
10171176
10181177 local all_healthy=true
@@ -1514,17 +1673,17 @@ open_shell() {
15141673show_access_info () {
15151674 echo
15161675 log_info " Technical service URLs (for advanced users):"
1517- echo " PGWatch Postgres: http://localhost:8080 "
1518- echo " PGWatch Prometheus: http://localhost:8089 "
1519- echo " Prometheus: http://localhost:9090 "
1520- echo " Flask API: http://localhost:5000 "
1676+ echo " PGWatch Postgres: http://localhost:58080 "
1677+ echo " PGWatch Prometheus: http://localhost:58089 "
1678+ echo " Prometheus: http://localhost:59090 "
1679+ echo " Flask API: http://localhost:55000 "
15211680
15221681 # Show target database only in demo mode
15231682 if is_demo_mode; then
1524- echo " Target Database: postgresql://postgres:postgres@localhost:5432 /target_database"
1683+ echo " Target Database: postgresql://postgres:postgres@localhost:55432 /target_database"
15251684 fi
15261685
1527- echo " Sink Database: postgresql://postgres:postgres@localhost:5433 /postgres"
1686+ echo " Sink Database: postgresql://postgres:postgres@localhost:55433 /postgres"
15281687 echo
15291688
15301689 # Show reports information
@@ -1549,7 +1708,18 @@ show_access_info() {
15491708 echo " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
15501709 echo -e " ${GREEN} 🚀 MAIN ACCESS POINT - Start here:${NC} "
15511710 echo -e " ${GREEN} Grafana Dashboard: http://localhost:3000${NC} "
1552- echo -e " ${GREEN} Login: demo / demo${NC} "
1711+
1712+ # Show custom credentials if available
1713+ if [ -f " $SCRIPT_DIR /.pgwatch-config" ]; then
1714+ local grafana_password=$( grep " ^grafana_password=" " $SCRIPT_DIR /.pgwatch-config" 2> /dev/null | cut -d' =' -f2)
1715+ if [ -n " $grafana_password " ]; then
1716+ echo -e " ${GREEN} Login: monitor / $grafana_password ${NC} "
1717+ else
1718+ echo -e " ${GREEN} Login: monitor / demo${NC} "
1719+ fi
1720+ else
1721+ echo -e " ${GREEN} Login: monitor / demo${NC} "
1722+ fi
15531723 echo " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
15541724}
15551725
@@ -1620,6 +1790,12 @@ main() {
16201790 " remove-key" )
16211791 remove_api_key
16221792 ;;
1793+ " generate-grafana-password" )
1794+ generate_grafana_password
1795+ ;;
1796+ " show-grafana-credentials" )
1797+ show_grafana_credentials
1798+ ;;
16231799 " help" |" --help" |" -h" )
16241800 show_help
16251801 ;;
0 commit comments