Containers
banshee/containers-collection/containers/kubernetes/https/
persistent-volume-claims
Whether each persistent volume claim of a Kubernetes cluster is bound, pending or lost, by its API.
par banshee1 installation1 version
v1Dernière
Publiée le 27 octobre 2026. First version.
// The persistent volume claims of a Kubernetes cluster, or of one namespace, by its API with the token of a
// service account (GET /api/v1/persistentvolumeclaims, or /api/v1/namespaces/<namespace>/...): whether each
// claim is bound to a volume, waits for one, or has lost it. A claim is named <namespace>/<claim>.
// The address is the API server's, the host's: https://<host:address>:<port>/.
need('protocol:http');
$address = need('host:address');
$token = need('protocol:http:token');
$port = variable('kubernetes:port', 'integer', array(
'label' => 'API port',
'help' => 'The port of the Kubernetes API server: 6443 for a cluster set up by kubeadm, often 443 for a managed one.',
'default' => 6443,
));
$namespace = variable('kubernetes:namespace', 'text', array(
'label' => 'Namespace',
'help' => 'Only the claims of this namespace, for a service account allowed in it alone. Empty: all namespaces.',
'required' => false,
));
per('claim', 'Claims');
output('phase', 'text', array('label' => 'Phase', 'per' => 'claim'));
output('capacity', 'text', array('label' => 'Capacity', 'per' => 'claim'));
watch.state('lost', 'Volume lost', 'phase', array('critical' => array('Lost')));
watch.state('pending', 'Claim not bound', 'phase', array(
'help' => 'Warning when a claim waits for a volume longer than the time given. A storage class that binds on first use leaves a claim pending until a pod uses it.',
'warning' => array('Pending'),
'for' => '15 min',
));
// The items of a list, read page by page: the API cuts a list at limit items and gives, under
// metadata.continue, the token of the next page, until the last. $query, when not empty, is added to the
// parameters of the address. The token goes in the header Authorization: Bearer; the answer is not secret,
// its body having carried none.
function api_list($base, $path, $query, $token) {
$items = array();
$next = '';
while (true) {
$url = $base . $path . '?limit=500';
if ($query != '') {
$url = $url . '&' . $query;
}
if ($next != '') {
$url = $url . '&continue=' . url.encode($next);
}
$answer = http.get($url, headers=array('Authorization' => 'Bearer ' . $token));
if ($answer['status'] == 401) {
fail('misconfigured', 'Kubernetes refuses the token, code 401');
}
if ($answer['status'] == 403) {
fail('misconfigured', 'The service account may not list ' . $path . ', code 403');
}
if ($answer['status'] != 200) {
fail('unreachable', 'Kubernetes answers ' . $path . ' with code ' . $answer['status']);
}
$page = json.read($answer['body']);
foreach ($page['items'] as $item) {
$items = list.add($items, $item);
}
$next = list.get($page['metadata'], 'continue', '');
if ($next == '') {
break;
}
}
return $items;
}
$path = '/api/v1/persistentvolumeclaims';
if ($namespace != '') {
$path = '/api/v1/namespaces/' . url.encode($namespace) . '/persistentvolumeclaims';
}
// {"metadata": {"namespace": "shop", "name": "data-db-0"}, "status": {"phase": "Bound", "capacity":
// {"storage": "10Gi"}}}. The phase is Pending, Bound or Lost; the capacity, that of the volume bound, as
// Kubernetes writes it.
foreach (api_list('https://' . $address . ':' . $port, $path, '', $token) as $claim) {
$name = $claim['metadata']['namespace'] . '/' . $claim['metadata']['name'];
$status = list.get($claim, 'status', array());
value('phase', list.get($status, 'phase', 'Pending'), $name);
$capacity = list.get($status, 'capacity', array());
if (list.has($capacity, 'storage')) {
value('capacity', $capacity['storage'], $name);
}
}