func PhysicalBackupMetadata()

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
}