Skip to main content
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,
  };
}

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 };
}

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.