1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package compose
import (
"context"
"errors"
"fmt"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/johnandersen777/socialweb-computer-kcp/api/v1alpha1"
"github.com/johnandersen777/socialweb-computer-kcp/internal/controllers/runtime/kube"
"github.com/johnandersen777/socialweb-computer-kcp/internal/controllers/runtime/manifests"
)
var ErrWorkloadDeleting = errors.New("compose: a set workload is being deleted; the set is applied once it is gone")
type Workload struct {
Kind string
Workspace string
Name string
}
var replaceableLost = map[v1alpha1.HostProcessLostReason]bool{v1alpha1.HostProcessLostUnitGone: true, v1alpha1.HostProcessLostHostRebooted: true,
v1alpha1.HostProcessLostManagerRestarted: true, v1alpha1.HostProcessLostIdentityMismatch: true}
func (c *Composer) SetWorkloads(setName, profile string, values any, include ...string) ([]Workload, error) {
set, err := infraSet(setName, profile, include)
if err != nil {
return nil, err
}
return c.renderWorkloads(set, values)
}
func (c *Composer) PhaseWorkloads(setName string, values any, phases ...string) ([]Workload, error) {
set, err := phaseSet(setName, phases)
if err != nil {
return nil, err
}
return c.renderWorkloads(set, values)
}
func (c *Composer) renderWorkloads(set manifests.Set, values any) ([]Workload, error) {
set.Base = c.Workspace()
rendered, err := set.Render(values)
if err != nil {
return nil, fmt.Errorf("compose: the workloads of set %s: %w", set.Name, err)
}
var out []Workload
for _, phase := range rendered {
for _, obj := range phase.Objects {
if u := obj.Unstructured; u != nil && (u.GetKind() == KindHostProcess || u.GetKind() == KindOpenBaoServer) {
out = append(out, Workload{Kind: u.GetKind(), Workspace: phase.Workspace, Name: u.GetName()})
}
}
}
return out, nil
}
func (c *Composer) CheckWorkloads(ctx context.Context, r Root) func([]Workload, error) (bool, error) {
return func(list []Workload, err error) (bool, error) {
if err != nil {
return false, err
}
intact, why, err := c.workloadsIntact(ctx, r, list)
if err != nil {
return false, err
}
if !intact {
c.log.Info("a set workload is missing or Lost; the set is applied again", "root", r.Owner(), "why", why)
c.Unapply(r)
}
return intact, nil
}
}
func (c *Composer) workloadsIntact(ctx context.Context, r Root, list []Workload) (bool, string, error) {
for _, w := range list {
switch w.Kind {
case KindHostProcess:
ri, err := c.Client(w.Workspace, HostProcessGVR)
if err != nil {
return false, "", err
}
hp, err := kube.Get[v1alpha1.HostProcess](ctx, ri, w.Name)
if apierrors.IsNotFound(err) {
return false, "HostProcess " + w.Name + " is missing", nil
}
if err != nil {
return false, "", err
}
if hp.DeletionTimestamp != nil {
return false, "", fmt.Errorf("%w: HostProcess %s", ErrWorkloadDeleting, w.Name)
}
if hp.Status.Phase == v1alpha1.HostProcessPhaseLost && replaceableLost[hp.Status.LostReason] {
if err := ri.Delete(ctx, w.Name, metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) {
return false, "", fmt.Errorf("compose: deleting the Lost HostProcess %s: %w", w.Name, err)
}
c.log.Info("a Lost set HostProcess is deleted to be placed again", "root", r.Owner(), "hostprocess", w.Name, "reason", hp.Status.LostReason)
return false, "HostProcess " + w.Name + " was Lost (" + string(hp.Status.LostReason) + ")", nil
}
case KindOpenBaoServer:
ri, err := c.Client(w.Workspace, OpenBaoServerGVR)
if err != nil {
return false, "", err
}
if _, err := kube.Get[v1alpha1.OpenBaoServer](ctx, ri, w.Name); apierrors.IsNotFound(err) {
return false, "OpenBaoServer " + w.Name + " is missing", nil
} else if err != nil {
return false, "", err
}
}
}
return true, "", nil
}
func (c *Composer) Unapply(r Root) {
c.mu.Lock()
defer c.mu.Unlock()
delete(c.applied, string(r.UID))
}