85 lines
3.5 KiB
Bash
Executable file
85 lines
3.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Read-only, secret-free evidence collector for the rails hosted by this reef.
|
|
# The cluster API is intentionally reached through the operator SSH path; 6443
|
|
# remains non-public. Override only when the approved executor name changes.
|
|
remote_host="${RAIL_RUNTIME_HOST:-railiance01}"
|
|
|
|
ssh -o BatchMode=yes "$remote_host" 'bash -s' <<'REMOTE'
|
|
set -euo pipefail
|
|
|
|
context="$(kubectl config current-context)"
|
|
server_version="$(kubectl version -o json | jq -r '.serverVersion.gitVersion')"
|
|
nodes="$(kubectl get nodes -o json)"
|
|
knative_deployments="$(kubectl -n knative-serving get deployments -o json)"
|
|
kourier_service="$(kubectl -n kourier-system get service kourier -o json)"
|
|
knative_services="$(kubectl get ksvc -A -o json)"
|
|
ingress_classes="$(kubectl get ingressclass -o json)"
|
|
storage_classes="$(kubectl get storageclass -o json)"
|
|
network_policy_count="$(kubectl get networkpolicy -A -o json | jq '.items | length')"
|
|
|
|
jq -n \
|
|
--arg context "$context" \
|
|
--arg server_version "$server_version" \
|
|
--argjson nodes "$nodes" \
|
|
--argjson deployments "$knative_deployments" \
|
|
--argjson kourier "$kourier_service" \
|
|
--argjson services "$knative_services" \
|
|
--argjson ingress_classes "$ingress_classes" \
|
|
--argjson storage_classes "$storage_classes" \
|
|
--argjson network_policy_count "$network_policy_count" \
|
|
'{
|
|
schema_version: "reef-railiance.rail-runtime-evidence/v1",
|
|
collected_at: (now | todateiso8601),
|
|
collector: "reef-railiance/tools/collect_rail_runtime_evidence.sh",
|
|
executor: "operator-ssh",
|
|
context: $context,
|
|
kubernetes: {
|
|
server_version: $server_version,
|
|
nodes: {
|
|
total: ($nodes.items | length),
|
|
ready: ([$nodes.items[] | select(any(.status.conditions[]; .type == "Ready" and .status == "True"))] | length),
|
|
members: [$nodes.items[] | {
|
|
name: .metadata.name,
|
|
roles: ([.metadata.labels | keys[] | select(startswith("node-role.kubernetes.io/")) | split("/")[1]] | sort),
|
|
kubelet_version: .status.nodeInfo.kubeletVersion,
|
|
allocatable: {
|
|
cpu: .status.allocatable.cpu,
|
|
memory: .status.allocatable.memory,
|
|
pods: .status.allocatable.pods
|
|
}
|
|
}]
|
|
},
|
|
ingress_classes: [$ingress_classes.items[].metadata.name] | sort,
|
|
storage_classes: [$storage_classes.items[].metadata.name] | sort,
|
|
network_policy_count: $network_policy_count
|
|
},
|
|
knative: {
|
|
deployments: [$deployments.items[] | {
|
|
name: .metadata.name,
|
|
desired: (.spec.replicas // 0),
|
|
available: (.status.availableReplicas // 0),
|
|
images: [.spec.template.spec.containers[].image]
|
|
}] | sort_by(.name),
|
|
all_deployments_available: (all($deployments.items[]; (.status.availableReplicas // 0) >= (.spec.replicas // 0))),
|
|
ingress: {
|
|
implementation: "net-kourier",
|
|
service_type: $kourier.spec.type,
|
|
cluster_ip: $kourier.spec.clusterIP
|
|
},
|
|
services: [$services.items[] | {
|
|
namespace: .metadata.namespace,
|
|
name: .metadata.name,
|
|
latest_created_revision: .status.latestCreatedRevisionName,
|
|
latest_ready_revision: .status.latestReadyRevisionName,
|
|
ready: (any(.status.conditions[]?; .type == "Ready" and .status == "True"))
|
|
}] | sort_by(.namespace, .name)
|
|
},
|
|
failure_domain: {
|
|
independent_members_observed: ($nodes.items | length),
|
|
result: (if ($nodes.items | length) > 1 then "requires-source-backed-review" else "fail-single-node" end)
|
|
},
|
|
secret_values_collected: false
|
|
}'
|
|
REMOTE
|