To generate a CSV report using the RedAPI, follow the steps below.
You will need a client ID for a RedAPI service account. If you do not have a service account, follow the steps in Article 1652 to create one.
The code sample is in C#, but can be customised as needed.
Important: We are planning to unify our authentication to support the CyberSentriq product suite, which will impact RedAPI report setups. Customers will be given sufficient notice to enable them to update their code. To ensure you stay informed on authentication changes, please let your account manager know when you start making use of the RedAPI for reporting.
1. Ensure that you have the following NuGet packages installed:
- IdentityModel/7.0.0
- Microsoft.IdentityModel.Tokens/8.3.0
- System.IdentityModel.Tokens.Jwt/8.3.0
- Swashbuckle.AspNetCore/7.2.0
2. Populate the code sample below based on your backup environment.
public class Program
{
public static async Task Main()
{
var outputPath = @"C:\Exports\"; //This is where the csv file will be saved
var tokenHttpClient = new HttpClient();
var date = DateTime.Now.ToString("yyyy-MM-dd");
Console.WriteLine("Input your company id: ");
var companyId = Console.ReadLine();
Console.WriteLine("Select report type: Type 1 for the backup report, type 2 for the restore report, type 3 for both");
var choice = Console.ReadLine();
//Authorization logic
const string ClientId = "InputYourClientIdHere";
const string JwkFilePath = @"PathToYourPrivateJwkFile";
const string Authority = "https://id.redstor.com";
var discoveryDocumentResponse = await tokenHttpClient.GetDiscoveryDocumentAsync(Authority);
if (discoveryDocumentResponse.IsError)
{
throw new Exception(discoveryDocumentResponse.Error);
}
var jwk = new JsonWebKey(await File.ReadAllTextAsync(JwkFilePath));
var now = DateTime.UtcNow;
var jwt = new JwtSecurityToken(ClientId, discoveryDocumentResponse.TokenEndpoint, new[]
{
new Claim(JwtClaimTypes.JwtId, CryptoRandom.CreateUniqueId()),
new Claim(JwtClaimTypes.Subject, ClientId),
new Claim(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(), ClaimValueTypes.Integer64)
},
now,
now.AddMinutes(5),
new SigningCredentials(jwk, SecurityAlgorithms.RsaSha256)
);
var assertion = new JwtSecurityTokenHandler().WriteToken(jwt);
var credentialResponse = await tokenHttpClient.RequestClientCredentialsTokenAsync(
new ClientCredentialsTokenRequest
{
Address = discoveryDocumentResponse.TokenEndpoint,
Scope = "api.read api.write",
ClientAssertion =
{
Type = OidcConstants.ClientAssertionTypes.JwtBearer,
Value = assertion
}
});
if (credentialResponse.IsError)
{
throw new Exception(credentialResponse.ErrorDescription);
}
var accessToken = credentialResponse.AccessToken!;
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true };
//Make a request to the backup status API endpoint
var backupStatusResults = new List<StatusItem>();
string? backupStatusResultsPageToken = null;
httpClient.BaseAddress = new Uri("https://api-gateway.redstor.com");
while (true)
{
var response = await httpClient.GetAsync($"backups/status?companyid={companyId}&maxResults=1&shouldReturnCount=false&apiVersion=2.0&pageToken={backupStatusResultsPageToken ?? ""}");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(json))
{
break;
}
var deserialized = JsonSerializer.Deserialize<StatusResponse>(json, JsonOptions);
if (deserialized == null)
{
break;
}
backupStatusResults.AddRange(deserialized.Results ?? []);
backupStatusResultsPageToken = deserialized.NextPageToken;
if (string.IsNullOrEmpty(backupStatusResultsPageToken))
{
break;
}
}
var backupStatusProps = typeof(StatusItem).GetProperties();
var backupStatusStringBuilder = new StringBuilder();
backupStatusStringBuilder.AppendLine(string.Join(",", backupStatusProps.Select(p => p.Name)));
foreach (var item in backupStatusResults)
backupStatusStringBuilder.AppendLine(string.Join(",", backupStatusProps.Select(p => p.GetValue(item))));
var backupStatusExport = backupStatusStringBuilder.ToString();
//Make a request to the backup status customer API endpoint
var backupStatusCustomerResults = new List<CustomerStatus>();
string? backupStatusCustomerResultsPageToken = null;
while (true)
{
var response = await httpClient.GetAsync($"backups/status/customers?companyid={companyId}&maxResults=1&shouldReturnCount=false&apiVersion=2.0&pageToken={backupStatusCustomerResultsPageToken}");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(json))
{
break;
}
var deserialized = JsonSerializer.Deserialize<StatusResponseMultipleCustomers>(json, JsonOptions);
if (deserialized == null)
{
break;
}
backupStatusCustomerResults.AddRange(deserialized.Results ?? []);
backupStatusCustomerResultsPageToken = deserialized.NextPageToken;
if (string.IsNullOrEmpty(backupStatusCustomerResultsPageToken))
{
break;
}
}
var backupStatusCustomerStringBuilder = new StringBuilder();
backupStatusCustomerStringBuilder.AppendLine("CompanyId,CompanyName,ProductName,ProductId,Succeeded,CompletedWithErrors,CompletedWithWarnings,Failed,Missed");
foreach (var customer in backupStatusCustomerResults)
foreach (var status in customer.Statuses)
backupStatusCustomerStringBuilder.AppendLine($"{customer.CompanyId},{customer.CompanyName},{status.ProductName},{status.ProductId},{status.Succeeded},{status.CompletedWithErrors},{status.CompletedWithWarnings},{status.Failed},{status.Missed}");
var backupStatusCustomerExport = backupStatusCustomerStringBuilder.ToString();
if (choice == "1" || choice == "3")
{
File.WriteAllText($"{outputPath}BackupStatus-{date}-{companyId}.csv", $"Company\n{backupStatusExport}\n \n Sub-Companies\n{backupStatusCustomerExport}");
}
//Make a request to the restore status API endpoint
var restoreStatusResults = new List<StatusItem>();
string? restoreStatusResultsPageToken = null;
while (true)
{
var response = await httpClient.GetAsync($"restores/status?companyid={companyId}&maxResults=1&shouldReturnCount=false&apiVersion=2.0&pageToken={restoreStatusResultsPageToken ?? ""}");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(json))
{
break;
}
var deserialized = JsonSerializer.Deserialize<StatusResponse>(json, JsonOptions);
if (deserialized == null)
{
break;
}
restoreStatusResults.AddRange(deserialized.Results ?? []);
restoreStatusResultsPageToken = deserialized.NextPageToken;
if (string.IsNullOrEmpty(restoreStatusResultsPageToken))
{
break;
}
}
var restoreStatusProps = typeof(StatusItem).GetProperties();
var restoreStatusStringBuilder = new StringBuilder();
restoreStatusStringBuilder.AppendLine(string.Join(",", restoreStatusProps.Select(p => p.Name)));
foreach (var item in restoreStatusResults)
restoreStatusStringBuilder.AppendLine(string.Join(",", restoreStatusProps.Select(p => p.GetValue(item))));
var restoreStatusExport = restoreStatusStringBuilder.ToString();
//Make a request to the restore status customer API endpoint
var restoreStatusCustomerResults = new List<CustomerStatus>();
string? restoreStatusCustomerResultsPageToken = null;
while (true)
{
var response = await httpClient.GetAsync($"restores/status/customers?companyid={companyId}&maxResults=1&shouldReturnCount=false&apiVersion=2.0&pageToken={restoreStatusCustomerResultsPageToken}");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(json))
{
break;
}
var deserialized = JsonSerializer.Deserialize<StatusResponseMultipleCustomers>(json, JsonOptions);
if (deserialized == null)
{
break;
}
restoreStatusCustomerResults.AddRange(deserialized.Results ?? []);
restoreStatusCustomerResultsPageToken = deserialized.NextPageToken;
if (string.IsNullOrEmpty(restoreStatusCustomerResultsPageToken))
{
break;
}
}
var restoreStatusCustomerStringBuilder = new StringBuilder();
restoreStatusCustomerStringBuilder.AppendLine("CompanyId,CompanyName,ProductName,ProductId,Succeeded,CompletedWithErrors,CompletedWithWarnings,Failed,Missed");
foreach (var customer in restoreStatusCustomerResults)
foreach (var status in customer.Statuses)
restoreStatusCustomerStringBuilder.AppendLine($"{customer.CompanyId},{customer.CompanyName},{status.ProductName},{status.ProductId},{status.Succeeded},{status.CompletedWithErrors},{status.CompletedWithWarnings},{status.Failed},{status.Missed}");
var restoreStatusCustomerExport = restoreStatusCustomerStringBuilder.ToString();
if (choice == "2" || choice == "3")
{
File.WriteAllText($"{outputPath}RestoreStatus-{date}-{companyId}.csv", $"Company\n{restoreStatusExport}\n \n Sub-Companies\n{restoreStatusCustomerExport}");
}
}
//Records
public record StatusResponse(string? NextPageToken, int TotalCount, List<StatusItem> Results);
public record StatusItem(int Succeeded, int CompletedWithErrors, int CompletedWithWarnings, int Failed, int Missed, string? ProductName, int ProductId);
public record StatusResponseMultipleCustomers(string? NextPageToken, int TotalCount, List<CustomerStatus> Results);
public record CustomerStatus(string? CompanyId, string? CompanyName, List<StatusItem> Statuses);
}3. The code will run as a console application. Input your company ID to get your results. The CSV file output will be saved to the folder you specified in outputPath.
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article