Rubrik
  • Products
  • Solutions
  • Knowledge Hub
  • About Us
  • CXO
  • Partners
  • Support
  • Contact Sales
Rubrik
LinkedInTwitterFacebookYouTubeInstagram

Call us at 1-844-478-2745

Submit Interest

ABOUT RUBRIK

CompanyLeadershipInvestor RelationsNewsroom & Press ReleasesCareersBlog

NEW TO RUBRIK

Why RubrikProductsSolutionsPartnersCustomersResources

POPULAR LINKS

Cyber RecoveryBackup & RecoveryRansomware Recovery Cloud Disaster RecoveryCloud Database Backup and Recovery ServiceSaaS Backups

CompanyLeadershipInvestor RelationsNewsroom & Press ReleasesCareersBlog
Why RubrikProductsSolutionsPartnersCustomersResources
Cyber RecoveryBackup & RecoveryRansomware Recovery Cloud Disaster RecoveryCloud Database Backup and Recovery ServiceSaaS Backups

CompanyLeadershipInvestor RelationsNewsroom & Press ReleasesCareersBlog
Why RubrikProductsSolutionsPartnersCustomersResources
Cyber RecoveryBackup & RecoveryRansomware Recovery Cloud Disaster RecoveryCloud Database Backup and Recovery ServiceSaaS Backups
  • Cookie Policy
  • Legal
  • Privacy Policy
  • Terms of Use
  • Trust
  • CA Residents only: Do not sell or share my personal information | Do not share my sensitive information

© 2026 Rubrik – Zero Trust Data Security™

Technical Blog Hub

Scaling rkGetSLAs() with Pagination, Retention, and Production-Ready SLA Data

TutorialServicesAPI-First Automation
JUN 10, 20264 min read
TutorialServicesAPI-First Automation
JUN 10, 20264 min read
Scaling rkGetSLAs() with Pagination, Retention, and Production-Ready SLA Data
Share
Background
Technical Blog Hub

Scaling rkGetSLAs() with Pagination, Retention, and Production-Ready SLA Data

TutorialServicesAPI-First Automation
JUN 10, 20264 min read
TutorialServicesAPI-First Automation
JUN 10, 20264 min read
Scaling rkGetSLAs() with Pagination, Retention, and Production-Ready SLA Data
Share

Table of Contents

Introduction

In Week 1, we rebooted the Rubrik PHP framework and defined a 12-week roadmap.

In Week 2, we explored the GraphQL schema and the Connection -> Node pattern that underpins the RSC API.

In Week 3, we built rkRscGetToken(), a production-ready OAuth2 authentication helper with token caching and environment-variable-based secret management.

In Week 4, we connected all the pieces and executed our first real GraphQL query from PHP. We introduced rkGetSLAs() as a minimal working implementation: id and name, no pagination, no retention detail.

We closed that post with a clear warning: "Working code is not the same as robust code."

This week, we make good on that promise.

We are extending rkGetSLAs() into a production-ready data access function by adding cursor-based pagination, normalized retention data, and clean CLI output. By the end of this post, the framework can retrieve the full SLA inventory from any RSC environment regardless of size, and expose it in a format that is immediately useful for reporting, compliance validation, and automation.

Why SLA Domains Are a Foundation Workload

SLA Domains are the central policy object in Rubrik Security Cloud. Every protected workload (VMware VMs, filesets, cloud workloads, databases) derives its protection behaviour from an SLA Domain assignment. The domain defines:

  • Frequency and retention duration
  • Local, replica, and archive targets
  • Protection policy enforcement logic

Being able to retrieve and normalize this data programmatically is a prerequisite for almost every operational workflow we will build later in this series: compliance reporting, inventory analysis, protection gap detection, and audit trails.

Even a basic SLA inventory immediately answers practical questions:

  • Which retention policies currently exist in the environment?
  • Are deprecated SLA Domains still present and potentially still assigned to workloads?
  • Are naming conventions being respected across teams?
  • Does the current SLA configuration align with internal protection standards?

These are not edge cases. They are day-one operational questions for any backup engineer managing RSC at scale.

The Query: SLA Domains with Pagination and Retention

In Week 4, we used the minimal slaDomains query: id and name only. Production environments require more.

We need retention data, and we need pagination to handle environments with large SLA inventories. Here is the extended query:

query ListSlas($first: Int!, $after: String) {
  slaDomains(first: $first, after: $after) {
    nodes {
      id
      name
      ... on GlobalSlaReply {
        localRetentionLimit {
          duration
          unit
        }
      }
      ... on ClusterSlaDomain {
        localRetentionLimit {
          duration
          unit
        }
      }
    }
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}

A few things worth understanding before writing PHP against this:

  • nodes contains the SLA objects, following the same Connection -> Node pattern from Week 2.
  • pageInfo drives pagination: hasNextPage signals whether more data exists, and endCursor is the cursor to pass on the next call.
  • Inline fragments (... on) are required because SLA Domains are a union type. GlobalSlaReply and ClusterSlaDomain are the two concrete implementations. Both expose localRetentionLimit, but they are distinct types and GraphQL requires you to be explicit.
  • localRetentionLimit returns duration (integer) and unit (string, e.g. DAYS).

If your environment still exposes slaDomainConnection, the structure is identical; only the field name changes.

 

Practitioner Tip

"When you encounter a union type in the RSC schema, the Playground immediately shows which concrete types implement it and what fields are available on each. Use it before writing inline fragments. It tells you exactly what to request and avoids silent misses on fields that exist only on one type."

Handling Pagination Correctly

This is the first function in the framework that implements cursor-based pagination in code. The pattern is straightforward, but it must be built from the start. Retrofitting it later means every caller that assumed a full dataset was silently working with incomplete data.

The loop logic:

  1. Initialize $after = null
  2. Execute the query with first: 100 and the current $after value
  3. Append nodes to the result array
  4. Read hasNextPage and endCursor from pageInfo
  5. If hasNextPage is true, advance $after to endCursor and repeat
  6. If false, exit
 

Practitioner Tip

"Always implement pagination from day one, even when you know the current dataset is small. APIs evolve, environments grow, and a function that silently truncates results at page one is worse than one that fails loudly. Silent data loss in a compliance report is exactly the class of bug you cannot afford to discover during an audit."

Normalizing Retention Data

The API returns retention as a structured object:

{
  "duration": 365,
  "unit": "DAYS"
}

Inside the framework, we normalize this into a single readable string: 365 DAYS. If no retention data is present (which can occur for SLA Domains without a defined local retention limit), we fall back to N/A.

Every consumer of rkGetSLAs() (reporting scripts, compliance checks, CLI tools) gets a consistent, predictable string rather than a nullable nested object. That consistency is what makes the function trustworthy as a data source across the framework.

Implementing rkGetSLAs()

Here is the full production implementation:

<?php

function rkGetSLAs(string $accessToken): array
{
    $allSlas = [];
    $after   = null;

    do
    {
        // ----------------------------------------
        // Build query with pagination variables
        // ----------------------------------------
        $query = <<<'GQL'
query ListSlas($first: Int!, $after: String) {
  slaDomains(first: $first, after: $after) {
    nodes {
      id
      name
      ... on GlobalSlaReply {
        localRetentionLimit {
          duration
          unit
        }
      }
      ... on ClusterSlaDomain {
        localRetentionLimit {
          duration
          unit
        }
      }
    }
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}
GQL;

        $variables = [
            'first' => 100,
            'after' => $after,
        ];

        // ----------------------------------------
        // Execute via shared GraphQL helper
        // ----------------------------------------
        $response = rkCallGraphQL($accessToken, $query, $variables);

        // ----------------------------------------
        // Validate response structure
        // ----------------------------------------
        if (!isset($response['data']['slaDomains']['nodes']))
        {
            throw new RuntimeException(
                'Unexpected GraphQL response structure in rkGetSLAs().'
            );
        }

        $nodes    = $response['data']['slaDomains']['nodes'];
        $pageInfo = $response['data']['slaDomains']['pageInfo'];

        // ----------------------------------------
        // Normalize each SLA Domain
        // ----------------------------------------
        foreach ($nodes as $node)
        {
            $retention = 'N/A';

            if (
                isset(
                    $node['localRetentionLimit']['duration'],
                    $node['localRetentionLimit']['unit']
                )
            )
            {
                $retention = $node['localRetentionLimit']['duration']
                    . ' '
                    . $node['localRetentionLimit']['unit'];
            }

            $allSlas[] = [
                'id'        => $node['id']   ?? '',
                'name'      => $node['name'] ?? '',
                'retention' => $retention,
            ];
        }

        // ----------------------------------------
        // Advance cursor or exit loop
        // ----------------------------------------
        $after = ($pageInfo['hasNextPage'] ?? false)
            ? ($pageInfo['endCursor'] ?? null)
            : null;

    } while ($after !== null);

    return $allSlas;
}

The function takes an access token, handles all pagination internally, and returns a clean, flat array. No caller needs to understand that cursor mechanics happened under the hood.

 

Practitioner Tip

"This is the contract a helper function should enforce: simple input, predictable output, zero API complexity visible to callers. The moment calling code has to understand cursor mechanics or inline fragments to consume a helper, the abstraction has failed."

CLI Output

Raw arrays serve programmatic consumers well. But readable output matters during development, validation, and operational spot-checks.

A simple CLI table turns the result of rkGetSLAs() into something you can scan instantly:

NAME                          | ID (short)        | RETENTION
----------------------------------------------------------------
Gold                          | 6f101e92…         | 365 DAYS
Silver                        | 1da44b73…         | 90 DAYS
Bronze                        | 0cc22d1b…         | 30 DAYS
No-Protection                 | 3b7a9f45…         | N/A

This is immediately useful: a visual SLA inventory, a quick validation tool, and a starting point for piping into scripts or audit exports.

 

Practitioner Tip

"Readable CLI output is underrated. Before building dashboards or integrations, make sure your data is easy to inspect manually. If it is not readable in the terminal, it is probably not structured cleanly enough to be trusted by the automation consuming it."

What This Week Really Delivers

The extended GraphQL query is not the milestone. It is straightforward.

The milestone is the structure surrounding it. With this week's work, the framework can now:

  • Retrieve the complete SLA inventory from any RSC environment regardless of size
  • Handle cursor-based pagination safely and transparently
  • Normalize API responses into clean, reusable data structures
  • Present operational output that is immediately usable

This is the first function in the framework that behaves like a production operational tool rather than an API demonstration. The pattern established here (paginate properly, normalize output, hide API complexity from callers) is the pattern every subsequent function will follow.

Commit of the Week

rkGetSLAs() extended: cursor-based pagination, retention normalization, clean CLI output.

What's Next

With SLA Domains fully queryable, the logical next step is connecting policies to actual protected objects.

In Week 6, we move into snapshot data. Using snappableConnection, RSC's unified query across all protected workload types, we will build rkGetSnapshotCount() to retrieve snapshot statistics for VMware VMs and filesets:

  • Total, local, SLA-driven, on-demand, replica, and archive snapshot counts
  • A single helper that works across multiple workload types without code changes
  • The foundation for compliance reporting, protection gap detection, and backup visibility workflows

This is where the framework transitions from data extraction to operational insight.

Contributed by

Frederic Lhoest
Frederic Lhoest

Senior Technology Architect, PCCW Global

Frederic is an automation expert and veteran architect with over 25 years of experience in streamlining data center operations and seamless workflows. He is a VMware and Nutanix AHV expert, with a proven track record of turning complex operational obstacles into efficient, automated systems. Beyond his technical role, he is a prominent speaker and leader in the Rubrik practitioner community, dedicated to fostering collaborative environments where real-world challenges meet innovative solutions.
Mike Preston
Mike Preston

Staff Technical Marketing Manager, Rubrik

Mike Preston is a Staff Technical Marketing Architect at Rubrik, leading the charge in all things Cloud and Automation. With an education focused on software engineering and over 25 years of IT operations experience, Mike strives to bridge the gap between development and operations — automating processes and streamlining workflows. He is the Toronto VMUG leader, author of Troubleshooting vSphere Storage, and an overall believer in sharing the knowledge!

Related Blogs

View all Posts
Reviving the Rubrik PHP Framework: The GraphQL Rebirth
Tutorial
APR 30, 2026

Reviving the Rubrik PHP Framework: The GraphQL Rebirth

Transition from REST to GraphQL with Rubrik Security Cloud. Explore a 12-week roadmap to build compliance dashboards, recovery portals, and advanced automation tools.

4 min read

Frederic Lhoest

Frederic Lhoest

Senior Technology Architect

PCCW Global

GraphQL 101 for Rubrik Security Cloud
Tutorial
APR 30, 2026

GraphQL 101 for Rubrik Security Cloud

Master GraphQL for Rubrik Security Cloud. Learn query vs. mutation patterns, the Connection-Node model, and expert tips for using the RSC API Playground and DevTools.

5 min read

Frederic Lhoest

Frederic Lhoest

Senior Technology Architect

PCCW Global

Talking to Rubrik Security Cloud: PHP Authentication with rkRscGetToken
Tutorial
MAY 13, 2026

Talking to Rubrik Security Cloud: PHP Authentication with rkRscGetToken

Learn how to build a secure, production-ready PHP authentication helper for Rubrik Security Cloud using OAuth2, token caching, and environment variables.

6 min read

Frederic Lhoest

Frederic Lhoest

Senior Technology Architect

PCCW Global

View all Posts

Share Your Insights

Have an interesting story or technical findings to share? Reach out to create a blog with us.

Learning & Certifications

Access free and instructor-led training and certification paths to master Rubrik products and maximise your data security expertise.

Explore coursesNext
Background

Share Your Insights

Have an interesting story or technical findings to share? Reach out to create a blog with us.

Learning & Certifications

Access free and instructor-led training and certification paths to master Rubrik products and maximise your data security expertise.

Explore coursesNext