Skip to content

Commit 3c29dc7

Browse files
committedJan 26, 2024
using awslab package to manage conditions
1 parent 63d44d0 commit 3c29dc7

File tree

8 files changed

+150
-45
lines changed

8 files changed

+150
-45
lines changed
 

‎api/v1alpha1/policyendpoint_types.go

+14-21
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package v1alpha1
1818

1919
import (
20+
"github.com/awslabs/operatorpkg/status"
2021
corev1 "k8s.io/api/core/v1"
2122
networking "k8s.io/api/networking/v1"
2223
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -105,7 +106,7 @@ type PolicyEndpointStatus struct {
105106
// Important: Run "make" to regenerate code after modifying this file
106107

107108
// +optional
108-
Conditions []PolicyEndpointCondition `json:"conditions,omitempty"`
109+
Conditions []status.Condition `json:"conditions,omitempty"`
109110
}
110111

111112
type PolicyEndpointConditionType string
@@ -115,26 +116,6 @@ const (
115116
Updated PolicyEndpointConditionType = "PatchedPolicyEndpoint"
116117
)
117118

118-
// PolicyEndpointCondition describes the state of a PolicyEndpoint at a certain point.
119-
// For example, binpacking PE slices should be updated as a condition change
120-
type PolicyEndpointCondition struct {
121-
// Type of PolicyEndpoint condition.
122-
// +optional
123-
Type PolicyEndpointConditionType `json:"type"`
124-
// Status of the condition, one of True, False, Unknown.
125-
// +optional
126-
Status corev1.ConditionStatus `json:"status"`
127-
// Last time the condition transitioned from one status to another.
128-
// +optional
129-
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
130-
// The reason for the condition's last transition.
131-
// +optional
132-
Reason string `json:"reason,omitempty"`
133-
// A human readable message indicating details about the transition.
134-
// +optional
135-
Message string `json:"message,omitempty"`
136-
}
137-
138119
//+kubebuilder:object:root=true
139120
//+kubebuilder:subresource:status
140121

@@ -159,3 +140,15 @@ type PolicyEndpointList struct {
159140
func init() {
160141
SchemeBuilder.Register(&PolicyEndpoint{}, &PolicyEndpointList{})
161142
}
143+
144+
func (s *PolicyEndpoint) GetConditions() []status.Condition {
145+
return []status.Condition(s.Status.Conditions)
146+
}
147+
148+
func (s *PolicyEndpoint) SetConditions(conds []status.Condition) {
149+
s.Status.Conditions = conds
150+
}
151+
152+
func (s *PolicyEndpoint) StatusConditions() status.ConditionSet {
153+
return status.NewReadyConditions().For(s)
154+
}

‎api/v1alpha1/zz_generated.deepcopy.go

+9-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎cmd/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func main() {
116116
os.Exit(1)
117117
}
118118

119-
policyEndpointsManager := policyendpoints.NewPolicyEndpointsManager(mgr.GetClient(),
119+
policyEndpointsManager := policyendpoints.NewPolicyEndpointsManager(ctx, mgr.GetClient(),
120120
controllerCFG.EndpointChunkSize, ctrl.Log.WithName("endpoints-manager"))
121121
finalizerManager := k8s.NewDefaultFinalizerManager(mgr.GetClient(), ctrl.Log.WithName("finalizer-manager"))
122122
policyController := controllers.NewPolicyReconciler(mgr.GetClient(), policyEndpointsManager,

‎config/crd/bases/networking.k8s.aws_policyendpoints.yaml

+45-10
Original file line numberDiff line numberDiff line change
@@ -232,28 +232,63 @@ spec:
232232
properties:
233233
conditions:
234234
items:
235-
description: PolicyEndpointCondition describes the state of a PolicyEndpoint
236-
at a certain point. For example, binpacking PE slices should be
237-
updated as a condition change
235+
description: Condition aliases the upstream type and adds additional
236+
helper methods
238237
properties:
239238
lastTransitionTime:
240-
description: Last time the condition transitioned from one status
241-
to another.
239+
description: lastTransitionTime is the last time the condition
240+
transitioned from one status to another. This should be when
241+
the underlying condition changed. If that is not known, then
242+
using the time when the API field changed is acceptable.
242243
format: date-time
243244
type: string
244245
message:
245-
description: A human readable message indicating details about
246-
the transition.
246+
description: message is a human readable message indicating
247+
details about the transition. This may be an empty string.
248+
maxLength: 32768
247249
type: string
250+
observedGeneration:
251+
description: observedGeneration represents the .metadata.generation
252+
that the condition was set based upon. For instance, if .metadata.generation
253+
is currently 12, but the .status.conditions[x].observedGeneration
254+
is 9, the condition is out of date with respect to the current
255+
state of the instance.
256+
format: int64
257+
minimum: 0
258+
type: integer
248259
reason:
249-
description: The reason for the condition's last transition.
260+
description: reason contains a programmatic identifier indicating
261+
the reason for the condition's last transition. Producers
262+
of specific condition types may define expected values and
263+
meanings for this field, and whether the values are considered
264+
a guaranteed API. The value should be a CamelCase string.
265+
This field may not be empty.
266+
maxLength: 1024
267+
minLength: 1
268+
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
250269
type: string
251270
status:
252-
description: Status of the condition, one of True, False, Unknown.
271+
description: status of the condition, one of True, False, Unknown.
272+
enum:
273+
- "True"
274+
- "False"
275+
- Unknown
253276
type: string
254277
type:
255-
description: Type of PolicyEndpoint condition.
278+
description: type of condition in CamelCase or in foo.example.com/CamelCase.
279+
--- Many .condition.type values are consistent across resources
280+
like Available, but because arbitrary conditions can be useful
281+
(see .node.status.conditions), the ability to deconflict is
282+
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
283+
maxLength: 316
284+
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
256285
type: string
286+
required:
287+
- lastTransitionTime
288+
- message
289+
- reason
290+
- status
291+
- type
257292
type: object
258293
type: array
259294
type: object

‎go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ require (
2121
)
2222

2323
require (
24+
github.com/awslabs/operatorpkg v0.0.0-20231211224023-fce5f0fa8592
2425
github.com/beorn7/perks v1.0.1 // indirect
2526
github.com/cespare/xxhash/v2 v2.2.0 // indirect
2627
github.com/davecgh/go-spew v1.1.1 // indirect

‎go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/awslabs/operatorpkg v0.0.0-20231211224023-fce5f0fa8592 h1:LSaLHzJ4IMZZLgVIx/2YIcvUCIAaE5OqLhjWzdwF060=
2+
github.com/awslabs/operatorpkg v0.0.0-20231211224023-fce5f0fa8592/go.mod h1:kqgbtyanB/ObfvsSUdGZOk1f3K807kvoibKoKX0wMK4=
13
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
24
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
35
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=

‎pkg/policyendpoints/manager.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"github.com/go-logr/logr"
1313
"github.com/pkg/errors"
1414
"github.com/samber/lo"
15-
corev1 "k8s.io/api/core/v1"
1615
networking "k8s.io/api/networking/v1"
1716
"k8s.io/apimachinery/pkg/api/equality"
1817
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -33,9 +32,10 @@ type PolicyEndpointsManager interface {
3332
}
3433

3534
// NewPolicyEndpointsManager constructs a new policyEndpointsManager
36-
func NewPolicyEndpointsManager(k8sClient client.Client, endpointChunkSize int, logger logr.Logger) *policyEndpointsManager {
35+
func NewPolicyEndpointsManager(ctx context.Context, k8sClient client.Client, endpointChunkSize int, logger logr.Logger) *policyEndpointsManager {
3736
endpointsResolver := resolvers.NewEndpointsResolver(k8sClient, logger.WithName("endpoints-resolver"))
3837
return &policyEndpointsManager{
38+
ctx: ctx,
3939
k8sClient: k8sClient,
4040
endpointsResolver: endpointsResolver,
4141
endpointChunkSize: endpointChunkSize,
@@ -59,6 +59,7 @@ const (
5959
var _ PolicyEndpointsManager = (*policyEndpointsManager)(nil)
6060

6161
type policyEndpointsManager struct {
62+
ctx context.Context
6263
k8sClient client.Client
6364
endpointsResolver resolvers.EndpointsResolver
6465
endpointChunkSize int
@@ -88,6 +89,12 @@ func (m *policyEndpointsManager) Reconcile(ctx context.Context, policy *networki
8889
if err := m.k8sClient.Create(ctx, &policyEndpoint); err != nil {
8990
return err
9091
}
92+
// initialize the PE's conditions
93+
conditions.CreatePEInitCondition(m.ctx,
94+
m.k8sClient,
95+
types.NamespacedName{Name: policyEndpoint.Name, Namespace: policyEndpoint.Namespace},
96+
m.logger,
97+
)
9198
m.logger.Info("Created policy endpoint", "id", k8s.NamespacedName(&policyEndpoint))
9299
}
93100

@@ -107,11 +114,13 @@ func (m *policyEndpointsManager) Reconcile(ctx context.Context, policy *networki
107114
peId,
108115
m.logger,
109116
policyinfo.Updated,
110-
corev1.ConditionFalse,
117+
metav1.ConditionFalse,
111118
reasonPatching,
112119
fmt.Sprintf("patching policy endpoint failed: %s", err.Error()),
120+
// keep condition history for error states
121+
true,
113122
); cErr != nil {
114-
m.logger.Error(cErr, "Adding PE patch failure condition updates to PE failed", "PENamespacedName", peId)
123+
m.logger.Error(cErr, "Adding PE patch failure condition updates to PE failed", "PENamespacedName", peId, "RV", policyEndpoint.ResourceVersion)
115124
}
116125
return err
117126
}
@@ -122,9 +131,11 @@ func (m *policyEndpointsManager) Reconcile(ctx context.Context, policy *networki
122131
peId,
123132
m.logger,
124133
policyinfo.Packed,
125-
corev1.ConditionTrue,
134+
metav1.ConditionTrue,
126135
reasonBinPacking,
127-
fmt.Sprintf("binpacked network policy endpoint slices on Ingress - %t, Egress - %t, PodSelector - %t", packed&ingBit>>ingressShift == 1, packed&egBit>>egressShift == 1, packed&psBit>>psShift == 1),
136+
fmt.Sprintf("binpacked network policy endpoint slices on Ingress - %t, Egress - %t, PodSelector - %t with RV %s", packed&ingBit>>ingressShift == 1, packed&egBit>>egressShift == 1, packed&psBit>>psShift == 1, policyEndpoint.ResourceVersion),
137+
// don't keep packing states history. if required, this can be changed to true later.
138+
false,
128139
); err != nil {
129140
m.logger.Error(err, "Adding bingpacking condition updates to PE failed", "PENamespacedName", peId)
130141
}

‎pkg/utils/conditions/conditions.go

+61-6
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,89 @@ package conditions
22

33
import (
44
"context"
5+
"time"
56

67
policyinfo "github.com/aws/amazon-network-policy-controller-k8s/api/v1alpha1"
8+
"github.com/awslabs/operatorpkg/status"
79
"github.com/go-logr/logr"
8-
corev1 "k8s.io/api/core/v1"
10+
"k8s.io/apimachinery/pkg/api/errors"
911
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1012
"k8s.io/apimachinery/pkg/types"
13+
"k8s.io/apimachinery/pkg/util/wait"
14+
"k8s.io/client-go/util/retry"
1115
"sigs.k8s.io/controller-runtime/pkg/client"
1216
)
1317

18+
const (
19+
jitterWaitTime = time.Millisecond * 100
20+
)
21+
22+
func CreatePEInitCondition(ctx context.Context, k8sClient client.Client, key types.NamespacedName, log logr.Logger) {
23+
// using a goroutine to add the condition with jitter wait.
24+
go func() {
25+
// since adding an init condition immediate after the PE is created
26+
// waiting for a small time before calling
27+
time.Sleep(wait.Jitter(jitterWaitTime, 0.25))
28+
err := retry.OnError(
29+
wait.Backoff{
30+
Duration: time.Millisecond * 100,
31+
Factor: 3.0,
32+
Jitter: 0.1,
33+
Steps: 5,
34+
Cap: time.Second * 10,
35+
},
36+
func(err error) bool { return errors.IsNotFound(err) },
37+
func() error {
38+
pe := &policyinfo.PolicyEndpoint{}
39+
var err error
40+
if err = k8sClient.Get(ctx, key, pe); err != nil {
41+
log.Error(err, "getting PE for conditions update failed", "PEName", pe.Name, "PENamespace", pe.Namespace)
42+
} else {
43+
copy := pe.DeepCopy()
44+
copy.StatusConditions()
45+
if err = k8sClient.Status().Patch(ctx, copy, client.MergeFrom(pe)); err != nil {
46+
log.Error(err, "creating PE init status failed", "PEName", pe.Name, "PENamespace", pe.Namespace)
47+
}
48+
}
49+
return err
50+
},
51+
)
52+
if err != nil {
53+
log.Error(err, "adding PE init condition failed after retries", "PENamespacedName", key)
54+
} else {
55+
log.Info("added PE init condition", "PENamespacedName", key)
56+
}
57+
}()
58+
}
59+
1460
func UpdatePEConditions(ctx context.Context, k8sClient client.Client, key types.NamespacedName, log logr.Logger,
1561
cType policyinfo.PolicyEndpointConditionType,
16-
cStatus corev1.ConditionStatus,
62+
cStatus metav1.ConditionStatus,
1763
cReason string,
18-
cMsg string) error {
64+
cMsg string,
65+
keepConditions bool) error {
1966
pe := &policyinfo.PolicyEndpoint{}
2067
var err error
2168
if err = k8sClient.Get(ctx, key, pe); err != nil {
2269
log.Error(err, "getting PE for conditions update failed", "PEName", pe.Name, "PENamespace", pe.Namespace)
2370
} else {
2471
copy := pe.DeepCopy()
25-
cond := policyinfo.PolicyEndpointCondition{
26-
Type: cType,
72+
cond := status.Condition{
73+
Type: string(cType),
2774
Status: cStatus,
2875
LastTransitionTime: metav1.Now(),
2976
Reason: cReason,
3077
Message: cMsg,
3178
}
32-
copy.Status.Conditions = append(copy.Status.Conditions, cond)
79+
if keepConditions {
80+
// not overwrite old conditions that have the same type
81+
conds := copy.GetConditions()
82+
conds = append(conds, cond)
83+
copy.SetConditions(conds)
84+
} else {
85+
// overwrite old conditions that have the same type
86+
copy.StatusConditions().Set(cond)
87+
}
3388
log.Info("the controller added condition to PE", "PEName", copy.Name, "PENamespace", copy.Namespace, "Conditions", copy.Status.Conditions)
3489
if err = k8sClient.Status().Patch(ctx, copy, client.MergeFrom(pe)); err != nil {
3590
log.Error(err, "updating PE status failed", "PEName", pe.Name, "PENamespace", pe.Namespace)

0 commit comments

Comments
 (0)
Failed to load comments.