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
package guestidentitygrant
import (
"context"
"errors"
"fmt"
"log/slog"
"time"
"k8s.io/apimachinery/pkg/api/equality"
"github.com/johnandersen777/socialweb-computer-kcp/api/v1alpha1"
ctlruntime "github.com/johnandersen777/socialweb-computer-kcp/internal/controllers/runtime"
"github.com/johnandersen777/socialweb-computer-kcp/internal/openbaoctl"
)
const (
Name = "guestidentitygrant"
Export = "computevms"
)
type Outcomes interface {
Outcome(cluster, name string) (v1alpha1.GuestIdentityGrantStatus, bool)
Forget(cluster, name string)
}
type Options struct {
Outcomes Outcomes
Events <-chan ctlruntime.Request
Scope func(workspace string) bool
Log *slog.Logger
}
type Controller struct {
log *slog.Logger
outcomes Outcomes
}
func New(opts Options) (*Controller, error) {
if opts.Outcomes == nil {
return nil, errors.New("guestidentitygrant: the grant outcomes of the OpenBaoServer controller are required")
}
log := opts.Log
if log == nil {
log = slog.New(slog.DiscardHandler)
}
return &Controller{log: log.With("component", "guestidentitygrant-controller"), outcomes: opts.Outcomes}, nil
}
func Register(m *ctlruntime.Manager, opts Options) (*Controller, error) {
ctl, err := New(opts)
if err != nil {
return nil, err
}
options := []ctlruntime.Option{ctlruntime.Export(Export), ctlruntime.Gone(ctl.gone)}
if opts.Events != nil {
options = append(options, ctlruntime.Events(opts.Events))
}
if opts.Scope != nil {
options = append(options, ctlruntime.InWorkspaces(opts.Scope))
}
if err := ctlruntime.For[*v1alpha1.GuestIdentityGrant](m, Name, ctl, options...); err != nil {
return nil, fmt.Errorf("guestidentitygrant: registering the GuestIdentityGrant controller: %w", err)
}
return ctl, nil
}
func (c *Controller) Reconcile(ctx context.Context, req ctlruntime.Request, object *v1alpha1.GuestIdentityGrant) (ctlruntime.Result, error) {
if !object.DeletionTimestamp.IsZero() {
return ctlruntime.Result{}, nil
}
outcome, ok := c.outcomes.Outcome(req.Cluster, object.Name)
if !ok || outcome.ObservedGeneration != object.Generation {
return ctlruntime.Result{}, nil
}
status := openbaoctl.MergeGrantStatus(object.Status, outcome, time.Now())
if equality.Semantic.DeepEqual(object.Status, status) {
return ctlruntime.Result{}, nil
}
next := object.DeepCopy()
next.Status = status
if err := req.ApplyStatus(ctx, next); err != nil {
return ctlruntime.Result{}, err
}
c.log.Info("the GuestIdentityGrant status follows its OpenBaoServer", "workspace", req.Workspace, "name", req.Name,
"applied", status.Applied, "role", status.Role)
return ctlruntime.Result{}, nil
}
func (c *Controller) gone(_ context.Context, req ctlruntime.Request) {
c.outcomes.Forget(req.Cluster, req.Name)
}