initDB inits a postgres database if not yet.
(pgDataDir, pgUser string)
| 72 | |
| 73 | // initDB inits a postgres database if not yet. |
| 74 | func initDB(pgDataDir, pgUser string) error { |
| 75 | versionPath := filepath.Join(pgDataDir, "PG_VERSION") |
| 76 | _, err := os.Stat(versionPath) |
| 77 | if err != nil && !os.IsNotExist(err) { |
| 78 | return errors.Wrapf(err, "failed to check postgres version in data directory path %q", versionPath) |
| 79 | } |
| 80 | initDone := err == nil |
| 81 | |
| 82 | // Skip initDB if setup already. |
| 83 | if initDone { |
| 84 | // If file permission was mutated before, postgres cannot start up. We should change file permissions to 0700 for all pgdata files. |
| 85 | if err := os.Chmod(pgDataDir, 0700); err != nil { |
| 86 | return errors.Wrapf(err, "failed to chmod postgres data directory %q to 0700", pgDataDir) |
| 87 | } |
| 88 | return nil |
| 89 | } |
| 90 | |
| 91 | // For pgDataDir and every intermediate to be created by MkdirAll, we need to prepare to chown |
| 92 | // it to the bytebase user. Otherwise, initdb will complain file permission error. |
| 93 | dirListToChown := []string{pgDataDir} |
| 94 | path := filepath.Dir(pgDataDir) |
| 95 | for path != "/" { |
| 96 | _, err := os.Stat(path) |
| 97 | if err == nil { |
| 98 | break |
| 99 | } |
| 100 | if !os.IsNotExist(err) { |
| 101 | return errors.Wrapf(err, "failed to check data directory path existence %q", path) |
| 102 | } |
| 103 | dirListToChown = append(dirListToChown, path) |
| 104 | path = filepath.Dir(path) |
| 105 | } |
| 106 | slog.Debug("Data directory list to Chown", slog.Any("dirListToChown", dirListToChown)) |
| 107 | |
| 108 | if err := os.MkdirAll(pgDataDir, 0700); err != nil { |
| 109 | return errors.Wrapf(err, "failed to make postgres data directory %q", pgDataDir) |
| 110 | } |
| 111 | |
| 112 | uid, gid, sameUser, err := shouldSwitchUser() |
| 113 | if err != nil { |
| 114 | return err |
| 115 | } |
| 116 | if !sameUser { |
| 117 | if uid > math.MaxInt32 || gid > math.MaxInt32 { |
| 118 | return errors.Errorf("uid %d or gid %d exceeds maximum safe value", uid, gid) |
| 119 | } |
| 120 | slog.Info(fmt.Sprintf("Recursively change owner of data directory %q to bytebase...", pgDataDir)) |
| 121 | for _, dir := range dirListToChown { |
| 122 | slog.Info(fmt.Sprintf("Change owner of %q to bytebase", dir)) |
| 123 | if err := os.Chown(dir, int(uid), int(gid)); err != nil { |
| 124 | return errors.Wrapf(err, "failed to change owner of %q to bytebase", dir) |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | args := []string{ |
| 130 | "-U", pgUser, |
| 131 | "-D", pgDataDir, |