Documentation Index Fetch the complete documentation index at: https://docs.cnap.tech/llms.txt
Use this file to discover all available pages before exploring further.
When managing multiple clusters, drift happens — different Kubernetes versions, mismatched images, inconsistent configurations. An agent can audit all clusters in parallel, comparing everything from node versions to installed CRDs.
Version Drift Check
An agent asked “are my clusters running the same versions?” fans out across all clusters in a single execute call:
async () => {
// Get all clusters
const clusters = await cnap . request ({
method: "GET" , path: "/v1/clusters"
}). then ( r => r . body . data );
const kube = ( clusterId , path ) => cnap . request ({
method: "GET" ,
path: `/v1/clusters/ ${ clusterId } /kube/ ${ path } ` ,
}). then ( r => r . body ). catch (() => null );
// Parallel fetch across all clusters
const results = await Promise . all ( clusters . map ( async ( cluster ) => {
const [ nodes , version ] = await Promise . all ([
kube ( cluster . id , "api/v1/nodes" ),
kube ( cluster . id , "version" ),
]);
if ( ! nodes ) return { cluster: cluster . name , status: "unreachable" };
return {
cluster: cluster . name ,
k8s_version: version ?. gitVersion ,
nodes: nodes . items . map ( n => ({
name: n . metadata . name ,
kubelet: n . status . nodeInfo . kubeletVersion ,
os: n . status . nodeInfo . osImage ,
runtime: n . status . nodeInfo . containerRuntimeVersion ,
kernel: n . status . nodeInfo . kernelVersion ,
})),
};
}));
// Find drift
const versions = [ ... new Set ( results . filter ( r => r . k8s_version ). map ( r => r . k8s_version ))];
return {
cluster_count: clusters . length ,
unique_k8s_versions: versions ,
drift_detected: versions . length > 1 ,
clusters: results ,
};
}
See all 42 lines
Image Consistency
Compare which container images are running across clusters — catch cases where one cluster is on v1.2.3 and another is still on v1.1.0:
async () => {
const clusters = await cnap . request ({
method: "GET" , path: "/v1/clusters"
}). then ( r => r . body . data );
const kube = ( clusterId , path ) => cnap . request ({
method: "GET" ,
path: `/v1/clusters/ ${ clusterId } /kube/ ${ path } ` ,
}). then ( r => r . body ). catch (() => null );
const results = await Promise . all ( clusters . map ( async ( cluster ) => {
const pods = await kube ( cluster . id , "api/v1/pods" );
if ( ! pods ) return { cluster: cluster . name , images: [] };
// Deduplicate images
const images = [ ... new Set (
pods . items . flatMap ( p =>
p . spec . containers . map ( c => c . image )
)
)]. sort ();
return { cluster: cluster . name , images };
}));
// Find images that differ across clusters
const allImages = new Map ();
for ( const r of results ) {
for ( const img of r . images ) {
const name = img . split ( ":" )[ 0 ];
if ( ! allImages . has ( name )) allImages . set ( name , new Map ());
allImages . get ( name ). set ( r . cluster , img );
}
}
const drift = [];
for ( const [ name , clusterVersions ] of allImages ) {
const tags = [ ... new Set ( clusterVersions . values ())];
if ( tags . length > 1 ) {
drift . push ({ image: name , versions: Object . fromEntries ( clusterVersions ) });
}
}
return { drift_count: drift . length , image_drift: drift };
}
See all 44 lines
CRD Comparison
Check which Custom Resource Definitions are installed in each cluster — useful for ensuring all clusters have the same operators and extensions:
async () => {
const clusters = await cnap . request ({
method: "GET" , path: "/v1/clusters"
}). then ( r => r . body . data );
const kube = ( clusterId , path ) => cnap . request ({
method: "GET" ,
path: `/v1/clusters/ ${ clusterId } /kube/ ${ path } ` ,
}). then ( r => r . body ). catch (() => null );
const results = await Promise . all ( clusters . map ( async ( cluster ) => {
const crds = await kube ( cluster . id , "apis/apiextensions.k8s.io/v1/customresourcedefinitions" );
return {
cluster: cluster . name ,
crds: crds ?. items . map ( c => c . metadata . name ). sort () || [],
};
}));
// Find CRDs unique to specific clusters
const allCrds = new Set ( results . flatMap ( r => r . crds ));
const missing = [];
for ( const crd of allCrds ) {
const present = results . filter ( r => r . crds . includes ( crd )). map ( r => r . cluster );
if ( present . length < results . length ) {
const absent = results . filter ( r => ! r . crds . includes ( crd )). map ( r => r . cluster );
missing . push ({ crd , present_in: present , missing_from: absent });
}
}
return { total_unique_crds: allCrds . size , inconsistencies: missing };
}
Why This Matters
Multi-cluster management typically requires dedicated tools — fleet managers, policy engines, GitOps controllers. For ad-hoc checks and audits, Code Mode gives agents the same cross-cluster visibility without any additional infrastructure.
The agent uses the CNAP API to list clusters, then fans out through each cluster’s kube proxy in parallel. It composes the comparison logic — version matching, image diffing, CRD set intersection — inside the sandbox. One conversation, full fleet visibility.