func (p *Process) assumePrimary(downstream *discoverd.Instance) (err error) { log := p.log.New("fn", "assumePrimary") if downstream != nil { log = log.New("downstream", downstream.Addr) } if p.running() && p.config().Role == state.RoleSync { log.Info("promoting to primary") if err := ioutil.WriteFile(p.triggerPath(), nil, 0655); err != nil { log.Error("error creating trigger file", "path", p.triggerPath(), "err", err) return err } p.waitForSync(downstream, true) return nil } log.Info("starting as primary") if p.running() { panic(fmt.Sprintf("unexpected state running role=%s", p.config().Role)) } if err := p.initDB(); err != nil { return err } if err := os.Remove(p.recoveryConfPath()); err != nil && !os.IsNotExist(err) { log.Error("error removing recovery.conf", "path", p.recoveryConfPath(), "err", err) return err } if err := p.writeConfig(configData{ReadOnly: downstream != nil}); err != nil { log.Error("error writing postgres.conf", "path", p.configPath(), "err", err) return err } if err := p.start(); err != nil { return err } var tx *pgx.Tx defer func() { if err != nil { if tx != nil { tx.Rollback() } p.db.Close() if err := p.stop(); err != nil { log.Debug("ignoring error stopping postgres", "err", err) } } }() tx, err = p.db.Begin() if err != nil { log.Error("error acquiring connection", "err", err) return err } if _, err := tx.Exec("SET TRANSACTION READ WRITE"); err != nil { log.Error("error setting transaction read-write", "err", err) return err } if _, err := tx.Exec(fmt.Sprintf(` DO $body$ BEGIN IF NOT EXISTS ( SELECT * FROM pg_catalog.pg_user WHERE usename = 'flynn') THEN CREATE USER flynn WITH SUPERUSER CREATEDB CREATEROLE REPLICATION PASSWORD '%s'; END IF; END $body$; `, p.password)); err != nil { log.Error("error creating superuser", "err", err) return err } if err := tx.Commit(); err != nil { log.Error("error committing transaction", "err", err) return err } if downstream != nil { p.waitForSync(downstream, true) } return nil }