@@ -563,62 +563,13 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
563563 options .Database = dbfake .New ()
564564 options .Pubsub = database .NewPubsubInMemory ()
565565 } else {
566- logger .Debug (ctx , "connecting to postgresql" )
567- sqlDB , err := sql .Open (sqlDriver , cfg .PostgresURL .Value )
566+ sqlDB , err := connectToPostgres (ctx , logger , sqlDriver , cfg .PostgresURL .Value )
568567 if err != nil {
569- return xerrors .Errorf ("dial postgres: %w" , err )
568+ return xerrors .Errorf ("connect to postgres: %w" , err )
570569 }
571- defer sqlDB .Close ()
572-
573- pingCtx , pingCancel := context .WithTimeout (ctx , 15 * time .Second )
574- defer pingCancel ()
575-
576- err = sqlDB .PingContext (pingCtx )
577- if err != nil {
578- return xerrors .Errorf ("ping postgres: %w" , err )
579- }
580-
581- // Ensure the PostgreSQL version is >=13.0.0!
582- version , err := sqlDB .QueryContext (ctx , "SHOW server_version;" )
583- if err != nil {
584- return xerrors .Errorf ("get postgres version: %w" , err )
585- }
586- if ! version .Next () {
587- return xerrors .Errorf ("no rows returned for version select" )
588- }
589- var versionStr string
590- err = version .Scan (& versionStr )
591- if err != nil {
592- return xerrors .Errorf ("scan version: %w" , err )
593- }
594- _ = version .Close ()
595- versionStr = strings .Split (versionStr , " " )[0 ]
596- if semver .Compare ("v" + versionStr , "v13" ) < 0 {
597- return xerrors .New ("PostgreSQL version must be v13.0.0 or higher!" )
598- }
599- logger .Debug (ctx , "connected to postgresql" , slog .F ("version" , versionStr ))
600-
601- err = migrations .Up (sqlDB )
602- if err != nil {
603- return xerrors .Errorf ("migrate up: %w" , err )
604- }
605- // The default is 0 but the request will fail with a 500 if the DB
606- // cannot accept new connections, so we try to limit that here.
607- // Requests will wait for a new connection instead of a hard error
608- // if a limit is set.
609- sqlDB .SetMaxOpenConns (10 )
610- // Allow a max of 3 idle connections at a time. Lower values end up
611- // creating a lot of connection churn. Since each connection uses about
612- // 10MB of memory, we're allocating 30MB to Postgres connections per
613- // replica, but is better than causing Postgres to spawn a thread 15-20
614- // times/sec. PGBouncer's transaction pooling is not the greatest so
615- // it's not optimal for us to deploy.
616- //
617- // This was set to 10 before we started doing HA deployments, but 3 was
618- // later determined to be a better middle ground as to not use up all
619- // of PGs default connection limit while simultaneously avoiding a lot
620- // of connection churn.
621- sqlDB .SetMaxIdleConns (3 )
570+ defer func () {
571+ _ = sqlDB .Close ()
572+ }()
622573
623574 options .Database = database .New (sqlDB )
624575 options .Pubsub , err = database .NewPubsub (ctx , sqlDB , cfg .PostgresURL .Value )
@@ -1007,7 +958,8 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
1007958 postgresBuiltinURLCmd .Flags ().BoolVar (& pgRawURL , "raw-url" , false , "Output the raw connection URL instead of a psql command." )
1008959 postgresBuiltinServeCmd .Flags ().BoolVar (& pgRawURL , "raw-url" , false , "Output the raw connection URL instead of a psql command." )
1009960
1010- root .AddCommand (postgresBuiltinURLCmd , postgresBuiltinServeCmd )
961+ createAdminUserCommand := newCreateAdminUserCommand ()
962+ root .AddCommand (postgresBuiltinURLCmd , postgresBuiltinServeCmd , createAdminUserCommand )
1011963
1012964 deployment .AttachFlags (root .Flags (), vip , false )
1013965
@@ -1607,3 +1559,71 @@ func buildLogger(cmd *cobra.Command, cfg *codersdk.DeploymentConfig) (slog.Logge
16071559 }
16081560 }, nil
16091561}
1562+
1563+ func connectToPostgres (ctx context.Context , logger slog.Logger , driver string , dbURL string ) (* sql.DB , error ) {
1564+ logger .Debug (ctx , "connecting to postgresql" )
1565+ sqlDB , err := sql .Open (driver , dbURL )
1566+ if err != nil {
1567+ return nil , xerrors .Errorf ("dial postgres: %w" , err )
1568+ }
1569+
1570+ ok := false
1571+ defer func () {
1572+ if ! ok {
1573+ _ = sqlDB .Close ()
1574+ }
1575+ }()
1576+
1577+ pingCtx , pingCancel := context .WithTimeout (ctx , 15 * time .Second )
1578+ defer pingCancel ()
1579+
1580+ err = sqlDB .PingContext (pingCtx )
1581+ if err != nil {
1582+ return nil , xerrors .Errorf ("ping postgres: %w" , err )
1583+ }
1584+
1585+ // Ensure the PostgreSQL version is >=13.0.0!
1586+ version , err := sqlDB .QueryContext (ctx , "SHOW server_version;" )
1587+ if err != nil {
1588+ return nil , xerrors .Errorf ("get postgres version: %w" , err )
1589+ }
1590+ if ! version .Next () {
1591+ return nil , xerrors .Errorf ("no rows returned for version select" )
1592+ }
1593+ var versionStr string
1594+ err = version .Scan (& versionStr )
1595+ if err != nil {
1596+ return nil , xerrors .Errorf ("scan version: %w" , err )
1597+ }
1598+ _ = version .Close ()
1599+ versionStr = strings .Split (versionStr , " " )[0 ]
1600+ if semver .Compare ("v" + versionStr , "v13" ) < 0 {
1601+ return nil , xerrors .New ("PostgreSQL version must be v13.0.0 or higher!" )
1602+ }
1603+ logger .Debug (ctx , "connected to postgresql" , slog .F ("version" , versionStr ))
1604+
1605+ err = migrations .Up (sqlDB )
1606+ if err != nil {
1607+ return nil , xerrors .Errorf ("migrate up: %w" , err )
1608+ }
1609+ // The default is 0 but the request will fail with a 500 if the DB
1610+ // cannot accept new connections, so we try to limit that here.
1611+ // Requests will wait for a new connection instead of a hard error
1612+ // if a limit is set.
1613+ sqlDB .SetMaxOpenConns (10 )
1614+ // Allow a max of 3 idle connections at a time. Lower values end up
1615+ // creating a lot of connection churn. Since each connection uses about
1616+ // 10MB of memory, we're allocating 30MB to Postgres connections per
1617+ // replica, but is better than causing Postgres to spawn a thread 15-20
1618+ // times/sec. PGBouncer's transaction pooling is not the greatest so
1619+ // it's not optimal for us to deploy.
1620+ //
1621+ // This was set to 10 before we started doing HA deployments, but 3 was
1622+ // later determined to be a better middle ground as to not use up all
1623+ // of PGs default connection limit while simultaneously avoiding a lot
1624+ // of connection churn.
1625+ sqlDB .SetMaxIdleConns (3 )
1626+
1627+ ok = true
1628+ return sqlDB , nil
1629+ }
0 commit comments