Skip to content

Commit

Permalink
Merge pull request #11 from Cdayz/add-tests
Browse files Browse the repository at this point in the history
Add unit tests for reconciller
  • Loading branch information
Cdayz authored Mar 2, 2024
2 parents 9f87f8d + 2a983b1 commit 5be68df
Show file tree
Hide file tree
Showing 7 changed files with 597 additions and 92 deletions.
13 changes: 8 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ require (
github.com/go-logr/zerologr v1.2.3
github.com/prometheus/client_golang v1.18.0
github.com/rs/zerolog v1.32.0
github.com/stretchr/testify v1.8.4
go.uber.org/automaxprocs v1.5.3
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.29.2
k8s.io/apimachinery v0.29.2
Expand Down Expand Up @@ -44,18 +46,19 @@ require (
github.com/onsi/ginkgo/v2 v2.14.0 // indirect
github.com/onsi/gomega v1.30.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/oauth2 v0.12.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.16.1 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
Expand Down
22 changes: 12 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,19 @@ go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnw
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -143,10 +145,10 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
Expand All @@ -159,8 +161,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
55 changes: 43 additions & 12 deletions internal/controller/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,78 @@ import (

const ControllerAnnotationImageNames = "cdayz.k8s.extensions/image-names"

func GetImageNamesFromAnnotation(obj metav1.Object) ([]string, error) {
var imageNames []string
type (
ImageName = string
PrePullImageResourceName = string
ImageNamesLookup struct {
Index map[PrePullImageResourceName]ImageName `json:"index"`
InvertedIndex map[ImageName][]PrePullImageResourceName `json:"invIndex"`
}
)

func GetImageNamesFromAnnotation(obj metav1.Object) (*ImageNamesLookup, error) {
var imageNames ImageNamesLookup
if imageNamesListStr, ok := obj.GetAnnotations()[ControllerAnnotationImageNames]; ok {
if err := json.Unmarshal([]byte(imageNamesListStr), &imageNames); err != nil {
return nil, fmt.Errorf("unmarshal image-names annotation: %w", err)
}
}
return imageNames, nil
return &imageNames, nil
}

func RemoveImageNameFromAnnotation(obj metav1.Object, name string) error {
func RemoveImageNameFromAnnotation(obj metav1.Object, imageName, objectName string) (*ImageNamesLookup, error) {
imageNames, err := GetImageNamesFromAnnotation(obj)
if err != nil {
return err
return nil, err
}

oldImageName, existsInIndex := imageNames.Index[objectName]
_, exitstInInvIndex := imageNames.InvertedIndex[oldImageName]

if !existsInIndex && !exitstInInvIndex {
return imageNames, nil
}

imageNames = slices.DeleteFunc(imageNames, func(s string) bool { return s == name })
delete(imageNames.Index, objectName)
imageNames.InvertedIndex[imageName] = slices.DeleteFunc(imageNames.InvertedIndex[imageName], func(s string) bool { return s == objectName })
if len(imageNames.InvertedIndex[imageName]) == 0 {
delete(imageNames.InvertedIndex, imageName)
}
imageNames.InvertedIndex[oldImageName] = slices.DeleteFunc(imageNames.InvertedIndex[oldImageName], func(s string) bool { return s == objectName })
if len(imageNames.InvertedIndex[oldImageName]) == 0 {
delete(imageNames.InvertedIndex, oldImageName)
}

val, err := MakeAnnotationValue(imageNames)
if err != nil {
return err
return nil, err
}

ann := obj.GetAnnotations()
ann[ControllerAnnotationImageNames] = val
obj.SetAnnotations(ann)

return nil
return imageNames, nil
}

func AddImageNameToAnnotation(obj metav1.Object, name string) (added bool, err error) {
func AddImageNameToAnnotation(obj metav1.Object, imageName, objectName string) (added bool, err error) {
imageNames, err := GetImageNamesFromAnnotation(obj)
if err != nil {
return false, err
}

if slices.Contains(imageNames, name) {
oldImageName, existInIndex := imageNames.Index[objectName]
if existInIndex && oldImageName == imageName && slices.Contains(imageNames.InvertedIndex[imageName], objectName) {
return false, nil
}

imageNames = append(imageNames, name)
imageNames.Index[objectName] = imageName
imageNames.InvertedIndex[oldImageName] = slices.DeleteFunc(imageNames.InvertedIndex[oldImageName], func(s string) bool { return s == objectName })
if len(imageNames.InvertedIndex[oldImageName]) == 0 {
delete(imageNames.InvertedIndex, oldImageName)
}

imageNames.InvertedIndex[imageName] = append(imageNames.InvertedIndex[imageName], objectName)
val, err := MakeAnnotationValue(imageNames)
if err != nil {
return false, err
Expand All @@ -63,7 +94,7 @@ func AddImageNameToAnnotation(obj metav1.Object, name string) (added bool, err e
return true, nil
}

func MakeAnnotationValue(imageNames []string) (string, error) {
func MakeAnnotationValue(imageNames *ImageNamesLookup) (string, error) {
imageNamesListBytes, err := json.Marshal(imageNames)
if err != nil {
return "", fmt.Errorf("marshal image-name annotation: %w", err)
Expand Down
25 changes: 18 additions & 7 deletions internal/controller/prepullimage_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import (
)

type PrePullImageController struct {
reconcileConfig *PrePullImageReconcilerConfig

kubeClient kubernetes.Interface
imClient imclientset.Interface

Expand All @@ -39,6 +37,8 @@ type PrePullImageController struct {

workers uint32
queueList []workqueue.RateLimitingInterface

reconciller prePullImageReconciller
}

func NewPrePullImageController(
Expand All @@ -61,8 +61,6 @@ func NewPrePullImageController(
podLister := podInformer.Lister()

cc := PrePullImageController{
reconcileConfig: reconcileConfig,

kubeClient: kubeClient,
imClient: imClient,

Expand All @@ -77,6 +75,12 @@ func NewPrePullImageController(

workers: workers,
queueList: queueList,

reconciller: prePullImageReconciller{
reconcileConfig: reconcileConfig,
kubeClient: kubeClient,
imClient: imClient,
},
}

_, _ = cc.prePullImageInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
Expand Down Expand Up @@ -173,7 +177,7 @@ func (cc *PrePullImageController) processNextReq(ctx context.Context, count uint
queue := cc.queueList[count]
obj, shutdown := queue.Get()
if shutdown {
klog.Errorf("Fail to pop item from queue")
klog.Errorf("fail to pop item from queue")
return false
}

Expand All @@ -190,12 +194,19 @@ func (cc *PrePullImageController) processNextReq(ctx context.Context, count uint

klog.V(3).Infof("try to handle request <%v>", req)

_, err := cc.Reconcile(ctx, req)
res, err := cc.reconciller.Reconcile(ctx, req)
if err != nil {
klog.V(2).Infof("Failed to handle PrePullImage<%s/%s>: %v", req.Namespace, req.Name, err)
klog.V(2).Infof("failed to handle PrePullImage<%s/%s>: %v", req.Namespace, req.Name, err)
// If any error, requeue it.
queue.AddRateLimited(req)
return true
} else if res.Requeue {
if res.RequeueAfter != 0 {
queue.AddAfter(req, res.RequeueAfter)
} else {
queue.AddRateLimited(req)
}
return true
}

// If no error, forget it.
Expand Down
12 changes: 6 additions & 6 deletions internal/controller/prepullimage_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ func (cc *PrePullImageController) addPod(obj interface{}) {
return
}

for _, imageName := range names {
name := ReconcileRequest{Namespace: pod.Namespace, Name: imageName, PodName: &pod.Name}
for name := range names.Index {
name := ReconcileRequest{Namespace: pod.Namespace, Name: name, PodName: &pod.Name}
queue := cc.getWorkerQueue(name.Key())
queue.Add(name)
}
Expand Down Expand Up @@ -105,8 +105,8 @@ func (cc *PrePullImageController) updatePod(oldObj, newObj interface{}) {
return
}

for _, imageName := range names {
name := ReconcileRequest{Namespace: newPod.Namespace, Name: imageName, PodName: &newPod.Name}
for name := range names.Index {
name := ReconcileRequest{Namespace: newPod.Namespace, Name: name, PodName: &newPod.Name}
queue := cc.getWorkerQueue(name.Key())
queue.Add(name)
}
Expand Down Expand Up @@ -138,8 +138,8 @@ func (cc *PrePullImageController) deletePod(obj interface{}) {
return
}

for _, imageName := range names {
name := ReconcileRequest{Namespace: pod.Namespace, Name: imageName, PodName: &pod.Name}
for name := range names.Index {
name := ReconcileRequest{Namespace: pod.Namespace, Name: name, PodName: &pod.Name}
queue := cc.getWorkerQueue(name.Key())
queue.Add(name)
}
Expand Down
Loading

0 comments on commit 5be68df

Please sign in to comment.