generated from mathias/template-go-web
feat(atlas): Phase C — live CD/deploy state on stage 07
Stage 07 now shows the pod's own live deploy state — deployed image tag + N/M replicas ready, green only when the rollout is fully ready — read from the k8s Deployment in-cluster (new namespaced deployments-read Role). DeployState/ DeployNode test-first; prepended to the authored CD narrative, fallback-safe. Verified: build/vet/lint(0)/test green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,66 @@ func HostsFromNodes(nodesJSON []byte) ([]Host, error) {
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
// Deploy is the live state of a Kubernetes Deployment.
|
||||
type Deploy struct {
|
||||
Image string
|
||||
Ready int
|
||||
Desired int
|
||||
}
|
||||
|
||||
// Tag is the image tag (substring after the last ":").
|
||||
func (d Deploy) Tag() string {
|
||||
if i := strings.LastIndex(d.Image, ":"); i >= 0 {
|
||||
return d.Image[i+1:]
|
||||
}
|
||||
return d.Image
|
||||
}
|
||||
|
||||
// DeployState parses a Kubernetes Deployment object into its live state.
|
||||
func DeployState(deployJSON []byte) (Deploy, error) {
|
||||
var dep struct {
|
||||
Spec struct {
|
||||
Replicas int `json:"replicas"`
|
||||
Template struct {
|
||||
Spec struct {
|
||||
Containers []struct {
|
||||
Image string `json:"image"`
|
||||
} `json:"containers"`
|
||||
} `json:"spec"`
|
||||
} `json:"template"`
|
||||
} `json:"spec"`
|
||||
Status struct {
|
||||
ReadyReplicas int `json:"readyReplicas"`
|
||||
} `json:"status"`
|
||||
}
|
||||
if err := json.Unmarshal(deployJSON, &dep); err != nil {
|
||||
return Deploy{}, fmt.Errorf("parse deployment: %w", err)
|
||||
}
|
||||
d := Deploy{Ready: dep.Status.ReadyReplicas, Desired: dep.Spec.Replicas}
|
||||
if len(dep.Spec.Template.Spec.Containers) > 0 {
|
||||
d.Image = dep.Spec.Template.Spec.Containers[0].Image
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// DeployNode renders the live deploy state as a stage node (green when the
|
||||
// rollout is fully ready, amber otherwise).
|
||||
func DeployNode(d Deploy) Node {
|
||||
pill := "var(--amber)"
|
||||
if d.Desired > 0 && d.Ready == d.Desired {
|
||||
pill = "var(--green)"
|
||||
}
|
||||
img := d.Image
|
||||
if i := strings.LastIndex(img, "/"); i >= 0 {
|
||||
img = img[i+1:] // drop registry host
|
||||
}
|
||||
return Node{
|
||||
Title: fmt.Sprintf("◆ deployed · %s · %d/%d ready", img, d.Ready, d.Desired),
|
||||
Pill: pill,
|
||||
Tags: []string{"live · k8s"},
|
||||
}
|
||||
}
|
||||
|
||||
// NamespaceSummary parses a Kubernetes `/api/v1/namespaces` list into a compact
|
||||
// "ns: a · b · c" line for the substrate, dropping system namespaces, sorting,
|
||||
// and capping the count (with "+N more" when it overflows).
|
||||
|
||||
Reference in New Issue
Block a user