Skip to content

Commit 3b402a2

Browse files
committed
Address linter feedback
Signed-off-by: Yury Tsarev <yury@upbound.io>
1 parent d4a4c96 commit 3b402a2

File tree

3 files changed

+139
-107
lines changed

3 files changed

+139
-107
lines changed

fn.go

Lines changed: 93 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@ package main
22

33
import (
44
"context"
5-
"crypto/md5"
65
"crypto/sha256"
76
"crypto/sha512"
87
"encoding/hex"
98
"encoding/json"
109
"hash"
1110
"strings"
1211

12+
"github.com/upbound/function-approve/input/v1beta1"
13+
1314
"github.com/crossplane/crossplane-runtime/pkg/errors"
1415
"github.com/crossplane/crossplane-runtime/pkg/logging"
1516
fnv1 "github.com/crossplane/function-sdk-go/proto/v1"
1617
"github.com/crossplane/function-sdk-go/request"
1718
"github.com/crossplane/function-sdk-go/resource"
1819
"github.com/crossplane/function-sdk-go/response"
19-
"github.com/upbound/function-approve/input/v1beta1"
2020
)
2121

2222
// Function implements the manual approval workflow function.
@@ -27,95 +27,141 @@ type Function struct {
2727
}
2828

2929
// RunFunction runs the Function.
30-
func (f *Function) RunFunction(ctx context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) {
30+
func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) {
3131
f.log.Info("Running function", "tag", req.GetMeta().GetTag())
3232

3333
rsp := response.To(req, response.DefaultTTL)
3434

35+
// Parse input and set up initial state
36+
in, err := f.initializeFunction(req, rsp)
37+
if err != nil {
38+
return rsp, nil //nolint:nilerr // errors are handled in rsp
39+
}
40+
41+
// Process hashing logic and get approval status
42+
newHash, oldHash, approved, err := f.processHashingAndApproval(req, in, rsp)
43+
if err != nil {
44+
return rsp, nil //nolint:nilerr // errors are handled in rsp
45+
}
46+
47+
// Check if changes need approval
48+
if f.needsApproval(approved, oldHash, newHash) {
49+
err := f.handleUnapprovedChanges(req, in, rsp, oldHash, newHash)
50+
if err != nil {
51+
return rsp, nil //nolint:nilerr // errors are handled in rsp
52+
}
53+
return rsp, nil
54+
}
55+
56+
// Handle approved changes
57+
err = f.handleApprovedChanges(req, in, rsp, newHash)
58+
if err != nil {
59+
return rsp, nil //nolint:nilerr // errors are handled in rsp
60+
}
61+
62+
return rsp, nil
63+
}
64+
65+
// initializeFunction parses input and initializes the function
66+
func (f *Function) initializeFunction(req *fnv1.RunFunctionRequest, rsp *fnv1.RunFunctionResponse) (*v1beta1.Input, error) {
3567
// Parse input and get defaults
3668
in, err := f.parseInput(req, rsp)
3769
if err != nil {
38-
return rsp, nil //nolint:nilerr // errors are handled in rsp
70+
return nil, err
3971
}
4072

4173
// Initialize response with desired XR and preserve context
4274
if err := f.initializeResponse(req, rsp); err != nil {
43-
return rsp, nil //nolint:nilerr // errors are handled in rsp
75+
return nil, err
4476
}
4577

78+
return in, nil
79+
}
80+
81+
// processHashingAndApproval handles hash computation and approval checks
82+
func (f *Function) processHashingAndApproval(req *fnv1.RunFunctionRequest, in *v1beta1.Input, rsp *fnv1.RunFunctionResponse) (newHash, oldHash string, approved bool, err error) {
4683
// Extract data to hash
4784
dataToHash, err := f.extractDataToHash(req, in, rsp)
4885
if err != nil {
49-
return rsp, nil //nolint:nilerr // errors are handled in rsp
86+
return "", "", false, err
5087
}
5188

5289
// Calculate hash
53-
newHash := f.calculateHash(dataToHash, in)
90+
newHash = f.calculateHash(dataToHash, in)
5491

5592
// Get old hash from status
56-
oldHash, err := f.getOldHash(req, in, rsp)
93+
oldHash, err = f.getOldHash(req, in, rsp)
5794
if err != nil {
58-
return rsp, nil //nolint:nilerr // errors are handled in rsp
95+
return "", "", false, err
5996
}
6097

6198
// Save new hash to status
6299
if err := f.saveNewHash(req, in, newHash, rsp); err != nil {
63-
return rsp, nil //nolint:nilerr // errors are handled in rsp
100+
return "", "", false, err
64101
}
65102

66103
// Check approval status
67-
approved, err := f.checkApprovalStatus(req, in, rsp)
104+
approved, err = f.checkApprovalStatus(req, in, rsp)
68105
if err != nil {
69-
return rsp, nil //nolint:nilerr // errors are handled in rsp
106+
return "", "", false, err
70107
}
71108

72-
// Reconciliation pause logic
73-
if !approved || (oldHash != "" && oldHash != newHash) {
74-
// Changes detected and not approved, pause reconciliation
75-
if err := f.pauseReconciliation(req, in, rsp); err != nil {
76-
return rsp, nil //nolint:nilerr // errors are handled in rsp
77-
}
109+
return newHash, oldHash, approved, nil
110+
}
78111

79-
// Set condition to show approval is needed
80-
msg := "Changes detected. Approval required."
81-
if in.ApprovalMessage != nil {
82-
msg = *in.ApprovalMessage
83-
}
112+
// needsApproval determines if the changes require approval
113+
func (f *Function) needsApproval(approved bool, oldHash, newHash string) bool {
114+
return !approved || (oldHash != "" && oldHash != newHash)
115+
}
84116

85-
condition := response.ConditionFalse(rsp, "ApprovalRequired", "WaitingForApproval").
86-
WithMessage(msg).
87-
TargetCompositeAndClaim()
117+
// handleUnapprovedChanges processes the case where changes need approval
118+
func (f *Function) handleUnapprovedChanges(req *fnv1.RunFunctionRequest, in *v1beta1.Input, rsp *fnv1.RunFunctionResponse, oldHash, newHash string) error {
119+
// Changes detected and not approved, pause reconciliation
120+
if err := f.pauseReconciliation(req, in, rsp); err != nil {
121+
return err
122+
}
88123

89-
if in.DetailedCondition != nil && *in.DetailedCondition {
90-
// Add detailed information about what changed and what needs approval
91-
detailedMsg := msg + "\nCurrent hash: " + newHash + "\n" +
92-
"Approved hash: " + oldHash + "\n" +
93-
"Approve this change by setting " + *in.ApprovalField + " to true"
94-
condition = condition.WithMessage(detailedMsg)
95-
}
124+
// Set condition to show approval is needed
125+
msg := "Changes detected. Approval required."
126+
if in.ApprovalMessage != nil {
127+
msg = *in.ApprovalMessage
128+
}
96129

97-
f.log.Debug("Pausing reconciliation asking for approval", "message", msg)
98-
// Return early, pausing reconciliation
99-
return rsp, nil
130+
condition := response.ConditionFalse(rsp, "ApprovalRequired", "WaitingForApproval").
131+
WithMessage(msg).
132+
TargetCompositeAndClaim()
133+
134+
if in.DetailedCondition != nil && *in.DetailedCondition {
135+
// Add detailed information about what changed and what needs approval
136+
detailedMsg := msg + "\nCurrent hash: " + newHash + "\n" +
137+
"Approved hash: " + oldHash + "\n" +
138+
"Approve this change by setting " + *in.ApprovalField + " to true"
139+
_ = condition.WithMessage(detailedMsg)
100140
}
101141

142+
f.log.Debug("Pausing reconciliation asking for approval", "message", msg)
143+
return nil
144+
}
145+
146+
// handleApprovedChanges processes the case where changes are approved
147+
func (f *Function) handleApprovedChanges(req *fnv1.RunFunctionRequest, in *v1beta1.Input, rsp *fnv1.RunFunctionResponse, newHash string) error {
102148
// If we got here, the changes are approved or there are no changes
103149
// Update the old hash with the new hash
104150
if err := f.saveOldHash(req, in, newHash, rsp); err != nil {
105-
return rsp, nil //nolint:nilerr // errors are handled in rsp
151+
return err
106152
}
107153

108154
// Remove pause annotation if it exists
109155
if err := f.resumeReconciliation(req, in, rsp); err != nil {
110-
return rsp, nil //nolint:nilerr // errors are handled in rsp
156+
return err
111157
}
112158

113159
// Set success condition
114160
response.ConditionTrue(rsp, "FunctionSuccess", "Success").
115161
WithMessage("Approved successfully").
116162
TargetCompositeAndClaim()
117163

118-
return rsp, nil
164+
return nil
119165
}
120166

121167
// parseInput parses the function input and sets defaults.
@@ -411,8 +457,6 @@ func (f *Function) calculateHash(data interface{}, in *v1beta1.Input) string {
411457
// Choose hash algorithm
412458
var h hash.Hash
413459
switch *in.HashAlgorithm {
414-
case "md5":
415-
h = md5.New()
416460
case "sha512":
417461
h = sha512.New()
418462
default:
@@ -434,10 +478,7 @@ func (f *Function) getOldHash(req *fnv1.RunFunctionRequest, in *v1beta1.Input, r
434478
}
435479

436480
// Remove status. prefix if present
437-
hashField := *in.OldHashField
438-
if strings.HasPrefix(hashField, "status.") {
439-
hashField = strings.TrimPrefix(hashField, "status.")
440-
}
481+
hashField := strings.TrimPrefix(*in.OldHashField, "status.")
441482

442483
// Get the old hash from status
443484
value, exists, err := GetNestedValue(xrStatus, hashField)
@@ -469,10 +510,7 @@ func (f *Function) saveNewHash(req *fnv1.RunFunctionRequest, in *v1beta1.Input,
469510
}
470511

471512
// Remove status. prefix if present
472-
hashField := *in.NewHashField
473-
if strings.HasPrefix(hashField, "status.") {
474-
hashField = strings.TrimPrefix(hashField, "status.")
475-
}
513+
hashField := strings.TrimPrefix(*in.NewHashField, "status.")
476514

477515
// Set the new hash in status
478516
if err := SetNestedValue(xrStatus, hashField, hash); err != nil {
@@ -504,10 +542,7 @@ func (f *Function) saveOldHash(req *fnv1.RunFunctionRequest, in *v1beta1.Input,
504542
}
505543

506544
// Remove status. prefix if present
507-
hashField := *in.OldHashField
508-
if strings.HasPrefix(hashField, "status.") {
509-
hashField = strings.TrimPrefix(hashField, "status.")
510-
}
545+
hashField := strings.TrimPrefix(*in.OldHashField, "status.")
511546

512547
// Set the old hash in status
513548
if err := SetNestedValue(xrStatus, hashField, hash); err != nil {
@@ -539,10 +574,7 @@ func (f *Function) checkApprovalStatus(req *fnv1.RunFunctionRequest, in *v1beta1
539574
}
540575

541576
// Remove status. prefix if present
542-
approvalField := *in.ApprovalField
543-
if strings.HasPrefix(approvalField, "status.") {
544-
approvalField = strings.TrimPrefix(approvalField, "status.")
545-
}
577+
approvalField := strings.TrimPrefix(*in.ApprovalField, "status.")
546578

547579
// Get the approval status
548580
value, exists, err := GetNestedValue(xrStatus, approvalField)
@@ -573,10 +605,10 @@ func (f *Function) pauseReconciliation(req *fnv1.RunFunctionRequest, in *v1beta1
573605
response.ConditionFalse(rsp, "Synced", "ReconciliationPaused").
574606
WithMessage("Resource synchronization paused due to pending approval").
575607
TargetCompositeAndClaim()
576-
608+
577609
return nil
578610
}
579-
611+
580612
// Otherwise use the pause annotation as before
581613
_, dxr, err := f.getXRAndStatus(req)
582614
if err != nil {
@@ -611,10 +643,10 @@ func (f *Function) resumeReconciliation(req *fnv1.RunFunctionRequest, in *v1beta
611643
response.ConditionTrue(rsp, "Synced", "ReconciliationResumed").
612644
WithMessage("Resource synchronization resumed after approval").
613645
TargetCompositeAndClaim()
614-
646+
615647
return nil
616648
}
617-
649+
618650
// Otherwise remove the pause annotation as before
619651
_, dxr, err := f.getXRAndStatus(req)
620652
if err != nil {

0 commit comments

Comments
 (0)