Skip to content

Commit

Permalink
introducing nmc package (#487) (#671)
Browse files Browse the repository at this point in the history
this package is used for creating, getting and manipulating
the NodeModulesConfig objects. Currently the added function
are the ones required by the module-nms reconcilaition,
but will be expanded in the subsequent commits
  • Loading branch information
yevgeny-shnaidman authored Jul 26, 2023
1 parent ce853bf commit 13b7708
Show file tree
Hide file tree
Showing 4 changed files with 396 additions and 0 deletions.
75 changes: 75 additions & 0 deletions internal/nmc/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package nmc

import (
"context"
"fmt"

k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

kmmv1beta1 "github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
)

//go:generate mockgen -source=helper.go -package=nmc -destination=mock_helper.go

type Helper interface {
Get(ctx context.Context, name string) (*kmmv1beta1.NodeModulesConfig, error)
SetNMCAsDesired(ctx context.Context, nmc *kmmv1beta1.NodeModulesConfig, namespace, name string, moduleConfig *kmmv1beta1.ModuleConfig) error
GetModuleEntry(nmc *kmmv1beta1.NodeModulesConfig, modNamespace, modName string) (*kmmv1beta1.NodeModuleSpec, int)
}

type helper struct {
client client.Client
}

func NewHelper(client client.Client) Helper {
return &helper{
client: client,
}
}

func (h *helper) Get(ctx context.Context, name string) (*kmmv1beta1.NodeModulesConfig, error) {
nmc := kmmv1beta1.NodeModulesConfig{}
err := h.client.Get(ctx, types.NamespacedName{Name: name}, &nmc)
if err != nil {
if k8serrors.IsNotFound(err) {
return nil, nil
}
return nil, fmt.Errorf("failed to get NodeModulesConfig %s: %v", name, err)
}
return &nmc, nil
}

func (h *helper) SetNMCAsDesired(ctx context.Context,
nmc *kmmv1beta1.NodeModulesConfig,
namespace string,
name string,
moduleConfig *kmmv1beta1.ModuleConfig) error {
foundEntry, index := h.GetModuleEntry(nmc, namespace, name)
// remove entry
if moduleConfig == nil {
if foundEntry != nil {
nmc.Spec.Modules = append(nmc.Spec.Modules[:index], nmc.Spec.Modules[index+1:]...)
}
return nil
}

// add/change entry
if foundEntry == nil {
nmc.Spec.Modules = append(nmc.Spec.Modules, kmmv1beta1.NodeModuleSpec{Name: name, Namespace: namespace})
foundEntry = &nmc.Spec.Modules[len(nmc.Spec.Modules)-1]
}
foundEntry.Config = *moduleConfig

return nil
}

func (h *helper) GetModuleEntry(nmc *kmmv1beta1.NodeModulesConfig, modNamespace, modName string) (*kmmv1beta1.NodeModuleSpec, int) {
for i, moduleSpec := range nmc.Spec.Modules {
if moduleSpec.Namespace == modNamespace && moduleSpec.Name == modName {
return &nmc.Spec.Modules[i], i
}
}
return nil, 0
}
218 changes: 218 additions & 0 deletions internal/nmc/helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package nmc

import (
"context"
"fmt"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
kmmv1beta1 "github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"

"github.com/golang/mock/gomock"
"github.com/rh-ecosystem-edge/kernel-module-management/internal/client"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
)

var _ = Describe("Get", func() {
var (
ctrl *gomock.Controller
clnt *client.MockClient
ctx context.Context
nmcHelper Helper
nmcName string
)

BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
clnt = client.NewMockClient(ctrl)
ctx = context.Background()
nmcHelper = NewHelper(clnt)
nmcName = "some name"
})

It("success", func() {
nsn := types.NamespacedName{Name: nmcName}
clnt.EXPECT().Get(ctx, nsn, gomock.Any()).DoAndReturn(
func(_ interface{}, _ interface{}, nm *kmmv1beta1.NodeModulesConfig, _ ...ctrlclient.GetOption) error {
nm.ObjectMeta = metav1.ObjectMeta{Name: nmcName}
return nil
},
)

res, err := nmcHelper.Get(ctx, nmcName)

Expect(err).NotTo(HaveOccurred())
Expect(res.Name).To(Equal(nmcName))
})

It("error", func() {
clnt.EXPECT().Get(ctx, types.NamespacedName{Name: nmcName}, gomock.Any()).Return(fmt.Errorf("some error"))

_, err := nmcHelper.Get(ctx, nmcName)

Expect(err).To(HaveOccurred())
})

It("no error, nmc does not exists", func() {
clnt.EXPECT().Get(ctx, types.NamespacedName{Name: nmcName}, gomock.Any()).Return(k8serrors.NewNotFound(schema.GroupResource{}, nmcName))

res, err := nmcHelper.Get(ctx, nmcName)

Expect(err).NotTo(HaveOccurred())
Expect(res).To(BeNil())
})

})

var _ = Describe("SetNMCAsDesired", func() {
var (
ctx context.Context
nmcHelper Helper
)

BeforeEach(func() {
ctx = context.Background()
nmcHelper = NewHelper(nil)
})

namespace := "test_namespace"
name := "test_name"

nmc := kmmv1beta1.NodeModulesConfig{}

It("adding new module", func() {
nmc.Spec.Modules = []kmmv1beta1.NodeModuleSpec{
{Name: "some name 1", Namespace: "some namespace 1"},
{Name: "some name 2", Namespace: "some namespace 2"},
}

moduleConfig := kmmv1beta1.ModuleConfig{InTreeModuleToRemove: "in-tree-module"}

err := nmcHelper.SetNMCAsDesired(ctx, &nmc, namespace, name, &moduleConfig)

Expect(err).NotTo(HaveOccurred())
Expect(len(nmc.Spec.Modules)).To(Equal(3))
Expect(nmc.Spec.Modules[2].Config.InTreeModuleToRemove).To(Equal("in-tree-module"))
})

It("changing existing module config", func() {
nmc.Spec.Modules = []kmmv1beta1.NodeModuleSpec{
{
Name: "some name 1",
Namespace: "some namespace 1",
},
{
Name: name,
Namespace: namespace,
Config: kmmv1beta1.ModuleConfig{InTreeModuleToRemove: "some-in-tree-module"},
},
}

moduleConfig := kmmv1beta1.ModuleConfig{InTreeModuleToRemove: "in-tree-module"}

err := nmcHelper.SetNMCAsDesired(ctx, &nmc, namespace, name, &moduleConfig)

Expect(err).NotTo(HaveOccurred())
Expect(len(nmc.Spec.Modules)).To(Equal(2))
Expect(nmc.Spec.Modules[1].Config.InTreeModuleToRemove).To(Equal("in-tree-module"))
})

It("deleting non-existent module", func() {
nmc.Spec.Modules = []kmmv1beta1.NodeModuleSpec{
{
Name: "some name 1",
Namespace: "some namespace 1",
Config: kmmv1beta1.ModuleConfig{InTreeModuleToRemove: "some-in-tree-module-1"},
},
{
Name: "some name 2",
Namespace: "some namespace 2",
Config: kmmv1beta1.ModuleConfig{InTreeModuleToRemove: "some-in-tree-module-2"},
},
}

err := nmcHelper.SetNMCAsDesired(ctx, &nmc, namespace, name, nil)

Expect(err).NotTo(HaveOccurred())
Expect(len(nmc.Spec.Modules)).To(Equal(2))
Expect(nmc.Spec.Modules[0].Config.InTreeModuleToRemove).To(Equal("some-in-tree-module-1"))
Expect(nmc.Spec.Modules[1].Config.InTreeModuleToRemove).To(Equal("some-in-tree-module-2"))
})

It("deleting existing module", func() {
nmc.Spec.Modules = []kmmv1beta1.NodeModuleSpec{
{
Name: "some name 1",
Namespace: "some namespace 1",
Config: kmmv1beta1.ModuleConfig{InTreeModuleToRemove: "some-in-tree-module-1"},
},
{
Name: name,
Namespace: namespace,
Config: kmmv1beta1.ModuleConfig{InTreeModuleToRemove: "some-in-tree-module-2"},
},
}

err := nmcHelper.SetNMCAsDesired(ctx, &nmc, namespace, name, nil)

Expect(err).NotTo(HaveOccurred())
Expect(len(nmc.Spec.Modules)).To(Equal(1))
Expect(nmc.Spec.Modules[0].Config.InTreeModuleToRemove).To(Equal("some-in-tree-module-1"))
})
})

var _ = Describe("GetModuleEntry", func() {
var (
nmcHelper Helper
)

BeforeEach(func() {
nmcHelper = NewHelper(nil)
})

It("empty module list", func() {
nmc := kmmv1beta1.NodeModulesConfig{
Spec: kmmv1beta1.NodeModulesConfigSpec{},
}

res, _ := nmcHelper.GetModuleEntry(&nmc, "namespace", "name")

Expect(res).To(BeNil())
})

It("module missing from the list", func() {
nmc := kmmv1beta1.NodeModulesConfig{
Spec: kmmv1beta1.NodeModulesConfigSpec{
Modules: []kmmv1beta1.NodeModuleSpec{
{Name: "some name 1", Namespace: "some namespace 1"},
{Name: "some name 2", Namespace: "some namespace 2"},
},
},
}

res, _ := nmcHelper.GetModuleEntry(&nmc, "namespace", "name")

Expect(res).To(BeNil())
})

It("module present", func() {
nmc := kmmv1beta1.NodeModulesConfig{
Spec: kmmv1beta1.NodeModulesConfigSpec{
Modules: []kmmv1beta1.NodeModuleSpec{
{Name: "some name 1", Namespace: "some namespace 1"},
{Name: "some name 2", Namespace: "some namespace 2"},
},
},
}

res, index := nmcHelper.GetModuleEntry(&nmc, "some namespace 1", "some name 1")

Expect(res.Name).To(Equal("some name 1"))
Expect(res.Namespace).To(Equal("some namespace 1"))
Expect(index).To(Equal(0))
})
})
80 changes: 80 additions & 0 deletions internal/nmc/mock_helper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions internal/nmc/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package nmc

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/rh-ecosystem-edge/kernel-module-management/internal/test"
"k8s.io/apimachinery/pkg/runtime"
)

var scheme *runtime.Scheme

func TestSuite(t *testing.T) {
RegisterFailHandler(Fail)

var err error

scheme, err = test.TestScheme()
Expect(err).NotTo(HaveOccurred())

RunSpecs(t, "NMC Suite")
}

0 comments on commit 13b7708

Please sign in to comment.