banshee is under active development: collectors will keep changing, and a version you publish will likely need adjustments. For stable use, wait for version 1.0.0.

Cloud

banshee/cloud-collection/cloud/google/https/

cloud-sql

The state of each Cloud SQL instance of a Google Cloud project, stopped told apart from running, by the Cloud SQL Admin API.

  • cloud
  • google
  • google-cloud
  • gcp
  • cloud-sql
  • databases
  • https
  • api

by banshee0 installations1 version

v1Latest

Published on October 27, 2026. First version.

Keen 1.0.0 · 74 lines
// The Cloud SQL instances of a Google Cloud project, by the Cloud SQL Admin API with a service account: the state
// of each instance, stopped told apart from running.
// Reads POST https://oauth2.googleapis.com/token by google.token, then GET
// https://sqladmin.googleapis.com/v1/projects/<project>/instances, page after page.
need('protocol:http');
need('protocol:google');
$project = variable('google:project', 'text', array(
    'label' => 'Project',
    'help'  => 'The ID of the Google Cloud project, as the console writes it under Project ID: my-project-123456.',
));

per('database', 'Databases');
output('state', 'text', array('label' => 'State', 'per' => 'database'));

watch.expect('not-running', 'Database not running', 'state', array('critical' => array('runnable'), 'for' => '2 runs'));
watch.missing('missing', 'Database missing', 'state', array('enabled' => false));

// The access token of the service account for this scope, asked by google.token and kept in the cache,
// encrypted on the poller, fifty minutes, under the hour Google gives it.
function access_token($scope) {
    if (cache.has('token')) {
        return cache.get('token');
    }
    $token = google.token($scope);
    cache.set('token', $token, 3000);
    return $token;
}

// One GET on a Google Cloud API with the token kept in the cache; a token Google no longer takes answers 401,
// and a new one is asked for, once.
function google_get($url, $scope, $what) {
    $answer = http.get($url, headers=array('Authorization' => 'Bearer ' . access_token($scope)));
    if ($answer['status'] == 401) {
        cache.delete('token');
        $answer = http.get($url, headers=array('Authorization' => 'Bearer ' . access_token($scope)));
    }
    if ($answer['status'] == 403) {
        fail('misconfigured', 'The service account may not read ' . $what . ', code 403',
            'Check its role on the project, and that the API is enabled on the project.');
    }
    if ($answer['status'] == 400 || $answer['status'] == 404) {
        fail('misconfigured', 'Google Cloud refuses to read ' . $what . ', code ' . $answer['status'],
            'Check the project and the names set on the probe.');
    }
    if ($answer['status'] != 200) {
        fail('unreachable', 'Google Cloud answers the reading of ' . $what . ' with code ' . $answer['status']);
    }
    return json.read($answer['body']);
}

// {"items": [{"name": "orders-db", "state": "RUNNABLE", "databaseVersion": "POSTGRES_16", "region":
// "europe-west1", "settings": {"activationPolicy": "ALWAYS", …}, …}], "nextPageToken": "…"}. An instance the owner
// stopped stays RUNNABLE, its activation policy set to NEVER: it is written stopped.
$base = 'https://sqladmin.googleapis.com/v1/projects/' . url.encode($project) . '/instances';
$token = '';
while (true) {
    $url = $base;
    if ($token != '') {
        $url = $base . '?' . url.query(array('pageToken' => $token));
    }
    $page = google_get($url, 'https://www.googleapis.com/auth/sqlservice.admin', 'the Cloud SQL instances');
    foreach (list.get($page, 'items', array()) as $instance) {
        $state = text.lower($instance['state']);
        $policy = list.get(list.get($instance, 'settings', array()), 'activationPolicy', '');
        if ($state == 'runnable' && $policy == 'NEVER') {
            $state = 'stopped';
        }
        value('state', $state, $instance['name']);
    }
    $token = list.get($page, 'nextPageToken', '');
    if ($token == '') {
        break;
    }
}