in oracle/controllers/config_agent_helpers.go [1335:1406]
func PhysicalBackupMetadata(ctx context.Context, r client.Reader, dbClientFactory DatabaseClientFactory, namespace, instName string, req PhysicalBackupMetadataRequest) (*PhysicalBackupMetadataResponse, error) {
klog.InfoS("config_agent_helpers/PhysicalBackupMetadata", "namespace", namespace, "instName", instName, "backupTag", req.BackupTag)
dbClient, closeConn, err := dbClientFactory.New(ctx, r, namespace, instName)
if err != nil {
return nil, fmt.Errorf("config_agent_helpers/PhysicalBackupMetadata: failed to create database daemon client: %v", err)
}
defer closeConn()
// Find the max "Next SCN" in current archivelog backup, this will be the backup scn.
// Example of list backup of archivelog output:
// Thrd Seq Low SCN Low Time Next SCN Next Time
// ---- ------- ---------- --------- ---------- ---------
// 1 1 1527386 30-JUL-21 1530961 30-JUL-21
listArchiveLogBackupCmd := "list backup of archivelog all tag '%s';"
res, err := dbClient.RunRMAN(ctx, &dbdpb.RunRMANRequest{Scripts: []string{fmt.Sprintf(listArchiveLogBackupCmd, req.BackupTag)}})
if err != nil {
return nil, fmt.Errorf("config_agent_helpers/PhysicalBackupMetadata: failed to list backup of archivelog: %v", err)
}
var threeLinesBuffer [3]string
maxSCN := int64(-1)
scanner := bufio.NewScanner(strings.NewReader(res.GetOutput()[0]))
for scanner.Scan() {
threeLinesBuffer[0] = threeLinesBuffer[1]
threeLinesBuffer[1] = threeLinesBuffer[2]
threeLinesBuffer[2] = scanner.Text()
if strings.Contains(threeLinesBuffer[0], "Next SCN") {
fields := strings.Fields(threeLinesBuffer[2])
if len(fields) != 6 {
return nil, fmt.Errorf("config_agent_helpers/PhysicalBackupMetadata: unexpected number of fields: %v", threeLinesBuffer[2])
}
currentSCN, err := strconv.ParseInt(fields[4], 10, 64)
if err != nil {
return nil, fmt.Errorf("config_agent_helpers/PhysicalBackupMetadata: failed to parse 'Next SCN' %v: %v", fields[2], err)
}
if currentSCN > maxSCN {
maxSCN = currentSCN
}
}
}
if maxSCN < 0 {
return nil, fmt.Errorf("config_agent_helpers/PhysicalBackupMetadata: failed to find backup scn")
}
scnToTimestampSQL := "select to_char(scn_to_timestamp(%s) at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as backuptime from dual"
backupTimeResp, err := fetchAndParseSingleResultQuery(ctx, dbClient, fmt.Sprintf(scnToTimestampSQL, strconv.FormatInt(maxSCN, 10)))
if err != nil {
return nil, fmt.Errorf("config_agent_helpers/PhysicalBackupMetadata: failed to query backup time: %s", err)
}
if backupTimeResp == "" {
return nil, nil
}
backupTime, err := time.Parse(time.RFC3339, backupTimeResp)
if err != nil {
return nil, fmt.Errorf("config_agent_helpers/PhysicalBackupMetadata: failed to parse backup time: %s", err)
}
incResp, err := FetchDatabaseIncarnation(ctx, r, dbClientFactory, namespace, instName)
if err != nil {
return nil, fmt.Errorf("config_agent_helpers/PhysicalBackupMetadata: failed to query database incarnation: %s", err)
}
klog.InfoS("config_agent_helpers/PhysicalBackupMetadata", "backup incarnation", incResp.Incarnation, "backup scn", maxSCN, "backup time", backupTime)
return &PhysicalBackupMetadataResponse{
BackupIncarnation: incResp.Incarnation,
BackupScn: strconv.FormatInt(maxSCN, 10),
BackupTimestamp: timestamppb.New(backupTime),
}, nil
}