/
verify.go
108 lines (90 loc) · 3.08 KB
/
verify.go
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
/*
Copyright (c) Microsoft Corporation.
Licensed under the MIT license.
*/
package testcommon
import (
"context"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/Azure/azure-service-operator/v2/internal/reflecthelpers"
"github.com/Azure/azure-service-operator/v2/pkg/genruntime"
"github.com/Azure/azure-service-operator/v2/pkg/genruntime/conditions"
)
type Verify struct {
kubeClient client.Client
}
func NewVerify(c client.Client) *Verify {
return &Verify{
kubeClient: c,
}
}
// HasState verifies that the provisioning state of the resource is in the target state.
func (e *Verify) HasState(
ctx context.Context,
obj client.Object,
desiredState metav1.ConditionStatus,
desiredSeverity conditions.ConditionSeverity,
oldGeneration int64,
) (bool, error) {
key := client.ObjectKeyFromObject(obj)
// In order to ensure that "old state" is cleared out from obj, we need to:
// 1. construct a newObj of the same type.
// 2. deserialize the kubeclient into newObj.
// 3. Use DeepCopyInto to copy newObj into obj (this ensures that nils from newObj make it onto obj, which
// doesn't happen normally with JSON deserialization).
newObj, err := genruntime.NewObjectFromExemplar(obj, e.kubeClient.Scheme())
if err != nil {
return false, err
}
err = e.kubeClient.Get(ctx, key, newObj)
if err != nil {
return false, err
}
// Assign the new stuff to obj by calling DeepCopyInto.
// This is relatively "safe" because DeepCopyObject() is a method required
// to reconcile a resource at all, and it internally uses DeepCopyInto. Places where
// this could fail are on types that don't use deepcopy-gen
reflecthelpers.DeepCopyInto(newObj, obj)
conditioner, ok := obj.(conditions.Conditioner)
if !ok {
return false, errors.Errorf("result of get was not conditions.Conditioner, was: %T", obj)
}
ready, ok := conditions.GetCondition(conditioner, conditions.ConditionTypeReady)
if !ok {
return false, nil
}
inGoalState := ready.Status == desiredState && ready.Severity == desiredSeverity
hasObservedGenerationChanged := oldGeneration != ready.ObservedGeneration
return inGoalState && hasObservedGenerationChanged, nil
}
// Deleted verifies that the object specified has been deleted
func (e *Verify) Deleted(ctx context.Context, obj client.Object) (bool, error) {
key := client.ObjectKeyFromObject(obj)
// Note that obj won't be modified if it's already deleted, so
// could be "stale" after this call
err := e.kubeClient.Get(ctx, key, obj)
if apierrors.IsNotFound(err) {
return true, nil
}
if err != nil {
return false, err
}
return false, nil
}
// AllDeleted verifies that all of the specified objects are deleted
func (e *Verify) AllDeleted(ctx context.Context, objs []client.Object) (bool, error) {
for _, obj := range objs {
// It's possible that this is horribly inefficient. Should be good enough for now though
deleted, err := e.Deleted(ctx, obj)
if err != nil {
return false, err
}
if !deleted {
return false, nil
}
}
return true, nil
}