Skip to content

Commit 846cd58

Browse files
committed
Update the support export tool to gather Patroni logs
Ensures that the on volume Patroni log file is exported, if that file exists. If the PostgresCluster is not configured to create this file, note in the debug logs that this is acceptable for some configurations. Issue: PGO-1701
1 parent 2e7b090 commit 846cd58

File tree

4 files changed

+149
-0
lines changed

4 files changed

+149
-0
lines changed

docs/content/reference/pgo_support_export.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ Collecting networkpolicies...
101101
Collecting limitranges...
102102
Collecting events...
103103
Collecting Postgres logs...
104+
Collecting pgBackRest logs...
105+
Collecting Patroni logs...
106+
Collecting pgBackRest Repo Host logs...
104107
Collecting PostgresCluster pod logs...
105108
Collecting monitoring pod logs...
106109
Collecting operator pod logs...

internal/cmd/exec.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ func (exec Executor) listBackrestLogFiles() (string, string, error) {
7979
return stdout.String(), stderr.String(), err
8080
}
8181

82+
// listPatroniLogFiles returns the full path of Patroni log file.
83+
// These are the Patroni logs stored on the Postgres instance.
84+
func (exec Executor) listPatroniLogFiles() (string, string, error) {
85+
var stdout, stderr bytes.Buffer
86+
87+
command := "ls -1dt pgdata/patroni/log/*"
88+
err := exec(nil, &stdout, &stderr, "bash", "-ceu", "--", command)
89+
90+
return stdout.String(), stderr.String(), err
91+
}
92+
8293
// listBackrestRepoHostLogFiles returns the full path of pgBackRest log files.
8394
// These are the pgBackRest logs stored on the repo host
8495
func (exec Executor) listBackrestRepoHostLogFiles() (string, string, error) {

internal/cmd/exec_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,25 @@ func TestListPGLogFiles(t *testing.T) {
7979

8080
}
8181

82+
func TestListPatroniLogFiles(t *testing.T) {
83+
84+
t.Run("default", func(t *testing.T) {
85+
expected := errors.New("pass-through")
86+
exec := func(
87+
stdin io.Reader, stdout, stderr io.Writer, command ...string,
88+
) error {
89+
assert.DeepEqual(t, command, []string{"bash", "-ceu", "--", "ls -1dt pgdata/patroni/log/*"})
90+
assert.Assert(t, stdout != nil, "should capture stdout")
91+
assert.Assert(t, stderr != nil, "should capture stderr")
92+
return expected
93+
}
94+
_, _, err := Executor(exec).listPatroniLogFiles()
95+
assert.ErrorContains(t, err, "pass-through")
96+
97+
})
98+
99+
}
100+
82101
func TestCatFile(t *testing.T) {
83102

84103
t.Run("default", func(t *testing.T) {

internal/cmd/export.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ Collecting networkpolicies...
282282
Collecting limitranges...
283283
Collecting events...
284284
Collecting Postgres logs...
285+
Collecting pgBackRest logs...
286+
Collecting Patroni logs...
287+
Collecting pgBackRest Repo Host logs...
285288
Collecting PostgresCluster pod logs...
286289
Collecting monitoring pod logs...
287290
Collecting operator pod logs...
@@ -471,6 +474,12 @@ Collecting PGO CLI logs...
471474
writeInfo(cmd, fmt.Sprintf("Error gathering pgBackRest DB Hosts Logs: %s", err))
472475
}
473476

477+
// Patroni Logs that are stored on the Postgres Instances
478+
err = gatherPatroniLogs(ctx, clientset, restConfig, namespace, clusterName, tw, cmd)
479+
if err != nil {
480+
writeInfo(cmd, fmt.Sprintf("Error gathering Patroni Logs from Instance Pods: %s", err))
481+
}
482+
474483
// All pgBackRest Logs on the Repo Host
475484
err = gatherRepoHostLogs(ctx, clientset, restConfig, namespace, clusterName, tw, cmd)
476485
if err != nil {
@@ -1308,6 +1317,113 @@ func gatherDbBackrestLogs(ctx context.Context,
13081317
return nil
13091318
}
13101319

1320+
// gatherPatroniLogs gathers all the file-based Patroni logs on the DB instance,
1321+
// if configured. By default, these logs will be sent to stdout and captured as
1322+
// Pod logs instead.
1323+
func gatherPatroniLogs(ctx context.Context,
1324+
clientset *kubernetes.Clientset,
1325+
config *rest.Config,
1326+
namespace string,
1327+
clusterName string,
1328+
tw *tar.Writer,
1329+
cmd *cobra.Command,
1330+
) error {
1331+
writeInfo(cmd, "Collecting Patroni logs...")
1332+
1333+
dbPods, err := clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{
1334+
LabelSelector: util.DBInstanceLabels(clusterName),
1335+
})
1336+
1337+
if err != nil {
1338+
if apierrors.IsForbidden(err) {
1339+
writeInfo(cmd, err.Error())
1340+
return nil
1341+
}
1342+
return err
1343+
}
1344+
1345+
if len(dbPods.Items) == 0 {
1346+
writeInfo(cmd, "No database instance pod found for gathering logs")
1347+
return nil
1348+
}
1349+
1350+
writeDebug(cmd, fmt.Sprintf("Found %d Pods\n", len(dbPods.Items)))
1351+
1352+
podExec, err := util.NewPodExecutor(config)
1353+
if err != nil {
1354+
return err
1355+
}
1356+
1357+
for _, pod := range dbPods.Items {
1358+
writeDebug(cmd, fmt.Sprintf("Pod Name is %s\n", pod.Name))
1359+
1360+
exec := func(stdin io.Reader, stdout, stderr io.Writer, command ...string,
1361+
) error {
1362+
return podExec(namespace, pod.Name, util.ContainerDatabase,
1363+
stdin, stdout, stderr, command...)
1364+
}
1365+
1366+
// Get Patroni Log Files
1367+
stdout, stderr, err := Executor(exec).listPatroniLogFiles()
1368+
1369+
// Depending upon the list* function above:
1370+
// An error may happen when err is non-nil or stderr is non-empty.
1371+
// In both cases, we want to print helpful information and continue to the
1372+
// next iteration.
1373+
if err != nil || stderr != "" {
1374+
1375+
if apierrors.IsForbidden(err) {
1376+
writeInfo(cmd, err.Error())
1377+
return nil
1378+
}
1379+
1380+
writeDebug(cmd, "Error getting Patroni logs\n")
1381+
1382+
if err != nil {
1383+
writeDebug(cmd, fmt.Sprintf("%s\n", err.Error()))
1384+
}
1385+
if stderr != "" {
1386+
writeDebug(cmd, stderr)
1387+
}
1388+
1389+
if strings.Contains(stderr, "No such file or directory") {
1390+
writeDebug(cmd, "Cannot find any Patroni log files. This is acceptable in some configurations.\n")
1391+
}
1392+
continue
1393+
}
1394+
1395+
logFiles := strings.Split(strings.TrimSpace(stdout), "\n")
1396+
for _, logFile := range logFiles {
1397+
writeDebug(cmd, fmt.Sprintf("LOG FILE: %s\n", logFile))
1398+
var buf bytes.Buffer
1399+
1400+
stdout, stderr, err := Executor(exec).catFile(logFile)
1401+
if err != nil {
1402+
if apierrors.IsForbidden(err) {
1403+
writeInfo(cmd, err.Error())
1404+
// Continue and output errors for each log file
1405+
// Allow the user to see and address all issues at once
1406+
continue
1407+
}
1408+
return err
1409+
}
1410+
1411+
buf.Write([]byte(stdout))
1412+
if stderr != "" {
1413+
str := fmt.Sprintf("\nError returned: %s\n", stderr)
1414+
buf.Write([]byte(str))
1415+
}
1416+
1417+
path := clusterName + fmt.Sprintf("/pods/%s/", pod.Name) + logFile
1418+
if err := writeTar(tw, buf.Bytes(), path, cmd); err != nil {
1419+
return err
1420+
}
1421+
}
1422+
1423+
}
1424+
return nil
1425+
}
1426+
13111427
// gatherRepoHostLogs gathers all the file-based pgBackRest logs on the repo host.
13121428
// There may not be any logs depending upon pgBackRest's log-level-file.
13131429
func gatherRepoHostLogs(ctx context.Context,

0 commit comments

Comments
 (0)