Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: unittest for k8s pkg #416

Merged
merged 15 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions pkg/builder/kaniko/kaniko.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"

"github.com/celestiaorg/knuu/pkg/builder"
"github.com/celestiaorg/knuu/pkg/k8s"
"github.com/celestiaorg/knuu/pkg/minio"
"github.com/celestiaorg/knuu/pkg/names"
)
Expand All @@ -31,10 +31,9 @@ const (
)

type Kaniko struct {
K8sClientset kubernetes.Interface
K8sNamespace string
Minio *minio.Minio // Minio service to store the build context if it's a directory
ContentName string // Name of the content pushed to Minio
K8s k8s.KubeManager
mojtaba-esk marked this conversation as resolved.
Show resolved Hide resolved
Minio *minio.Minio // Minio service to store the build context if it's a directory
ContentName string // Name of the content pushed to Minio
}

var _ builder.Builder = &Kaniko{}
Expand All @@ -45,7 +44,7 @@ func (k *Kaniko) Build(ctx context.Context, b *builder.BuilderOptions) (logs str
return "", ErrPreparingJob.Wrap(err)
}

cJob, err := k.K8sClientset.BatchV1().Jobs(k.K8sNamespace).Create(ctx, job, metav1.CreateOptions{})
cJob, err := k.K8s.Clientset().BatchV1().Jobs(k.K8s.Namespace()).Create(ctx, job, metav1.CreateOptions{})
if err != nil {
return "", ErrCreatingJob.Wrap(err)
}
Expand Down Expand Up @@ -77,7 +76,7 @@ func (k *Kaniko) Build(ctx context.Context, b *builder.BuilderOptions) (logs str
}

func (k *Kaniko) waitForJobCompletion(ctx context.Context, job *batchv1.Job) (*batchv1.Job, error) {
watcher, err := k.K8sClientset.BatchV1().Jobs(k.K8sNamespace).Watch(ctx, metav1.ListOptions{
watcher, err := k.K8s.Clientset().BatchV1().Jobs(k.K8s.Namespace()).Watch(ctx, metav1.ListOptions{
FieldSelector: fmt.Sprintf("metadata.name=%s", job.Name),
})
if err != nil {
Expand Down Expand Up @@ -108,7 +107,7 @@ func (k *Kaniko) waitForJobCompletion(ctx context.Context, job *batchv1.Job) (*b
}

func (k *Kaniko) firstPodFromJob(ctx context.Context, job *batchv1.Job) (*v1.Pod, error) {
podList, err := k.K8sClientset.CoreV1().Pods(k.K8sNamespace).List(ctx, metav1.ListOptions{
podList, err := k.K8s.Clientset().CoreV1().Pods(k.K8s.Namespace()).List(ctx, metav1.ListOptions{
LabelSelector: fmt.Sprintf("job-name=%s", job.Name),
})
if err != nil {
Expand All @@ -131,7 +130,7 @@ func (k *Kaniko) containerLogs(ctx context.Context, pod *v1.Pod) (string, error)
Container: pod.Spec.Containers[0].Name,
}

req := k.K8sClientset.CoreV1().Pods(k.K8sNamespace).GetLogs(pod.Name, &logOptions)
req := k.K8s.Clientset().CoreV1().Pods(k.K8s.Namespace()).GetLogs(pod.Name, &logOptions)
logs, err := req.DoRaw(ctx)
if err != nil {
return "", err
Expand All @@ -141,7 +140,7 @@ func (k *Kaniko) containerLogs(ctx context.Context, pod *v1.Pod) (string, error)
}

func (k *Kaniko) cleanup(ctx context.Context, job *batchv1.Job) error {
err := k.K8sClientset.BatchV1().Jobs(k.K8sNamespace).
err := k.K8s.Clientset().BatchV1().Jobs(k.K8s.Namespace()).
Delete(ctx, job.Name, metav1.DeleteOptions{
PropagationPolicy: &[]metav1.DeletionPropagation{metav1.DeletePropagationBackground}[0],
})
Expand All @@ -150,7 +149,7 @@ func (k *Kaniko) cleanup(ctx context.Context, job *batchv1.Job) error {
}

// Delete the associated Pods
err = k.K8sClientset.CoreV1().Pods(k.K8sNamespace).
err = k.K8s.Clientset().CoreV1().Pods(k.K8s.Namespace()).
DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{
LabelSelector: fmt.Sprintf("job-name=%s", job.Name),
})
Expand Down
48 changes: 19 additions & 29 deletions pkg/builder/kaniko/kaniko_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,23 @@ import (
"k8s.io/client-go/kubernetes/fake"

"github.com/celestiaorg/knuu/pkg/builder"
"github.com/celestiaorg/knuu/pkg/k8s"
)

const (
k8sNamespace = "test-namespace"
k8sNamespace = "test-namespace"
testImage = "test-image"
testDestination = "registry.example.com/test-image:latest"
)

func TestKanikoBuilder(t *testing.T) {
k8sCS := fake.NewSimpleClientset()
k8sClient, err := k8s.NewClientCustom(context.Background(), k8sCS, k8sCS.Discovery(), nil, k8sNamespace)
require.NoError(t, err)
kb := &Kaniko{
MSevey marked this conversation as resolved.
Show resolved Hide resolved
K8sClientset: k8sCS,
K8sNamespace: k8sNamespace,
K8s: k8sClient,
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
ctx := context.Background()

t.Run("BuildSuccess", func(t *testing.T) {
blCtx := "git://github.com/mojtaba-esk/sample-docker"
Expand All @@ -36,9 +39,9 @@ func TestKanikoBuilder(t *testing.T) {
require.NoError(t, err, "GetDefaultCacheOptions should succeed")

buildOptions := &builder.BuilderOptions{
ImageName: "test-image",
ImageName: testImage,
BuildContext: blCtx,
Destination: "registry.example.com/test-image:latest",
Destination: testDestination,
Args: []string{"--build-arg=value"},
Cache: cacheOpts,
}
Expand All @@ -54,7 +57,7 @@ func TestKanikoBuilder(t *testing.T) {
}()

// Simulate the successful completion of the Job after a short delay
time.Sleep(2 * time.Second)
time.Sleep(500 * time.Millisecond)
completeAllJobInFakeClientset(t, k8sCS, k8sNamespace)

wg.Wait()
Expand All @@ -63,40 +66,27 @@ func TestKanikoBuilder(t *testing.T) {
assert.NotEmpty(t, logs, "Build logs should not be empty")
})

t.Run("BuildFailure", func(t *testing.T) {
buildOptions := &builder.BuilderOptions{
ImageName: "test-image",
BuildContext: "invalid-context", // Simulate an invalid context
Destination: "registry.example.com/test-image:latest",
}

logs, err := kb.Build(ctx, buildOptions)

assert.Error(t, err, "Build should fail")
assert.Empty(t, logs, "Build logs should be empty")
})

t.Run("BuildWithContextCancellation", func(t *testing.T) {
buildOptions := &builder.BuilderOptions{
ImageName: "test-image",
ImageName: testImage,
BuildContext: "git://example.com/repo",
Destination: "registry.example.com/test-image:latest",
Destination: testDestination,
}

// Cancel the context to simulate cancellation during the build
ctx, cancel := context.WithCancel(ctx)
cancel()

logs, err := kb.Build(ctx, buildOptions)

assert.Error(t, err, "Build should fail due to context cancellation")
assert.Empty(t, logs, "Build logs should be empty")
assert.Error(t, err, "build should fail due to context cancellation")
assert.Empty(t, logs, "build logs should be empty")
})

}

func completeAllJobInFakeClientset(t *testing.T, clientset *fake.Clientset, namespace string) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
ctx := context.Background()

job, err := clientset.BatchV1().Jobs(namespace).List(ctx, metav1.ListOptions{})
assert.NoError(t, err)
Expand Down Expand Up @@ -125,8 +115,8 @@ func createPodFromJob(job *batchv1.Job) *v1.Pod {
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "fake-container", // Adjust as needed
Image: "fake-image", // Adjust as needed
Name: "fake-container",
Image: "fake-image",
},
},
},
Expand Down
38 changes: 19 additions & 19 deletions pkg/instance/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (i *Instance) deployService(ctx context.Context, portsTCP, portsUDP []int)
labels := i.getLabels()
labelSelectors := labels

service, err := i.K8sCli.CreateService(ctx, serviceName, labels, labelSelectors, portsTCP, portsUDP)
service, err := i.K8sClient.CreateService(ctx, serviceName, labels, labelSelectors, portsTCP, portsUDP)
if err != nil {
return ErrDeployingService.WithParams(i.k8sName).Wrap(err)
}
Expand All @@ -111,7 +111,7 @@ func (i *Instance) patchService(ctx context.Context, portsTCP, portsUDP []int) e
labels := i.getLabels()
labelSelectors := labels

service, err := i.K8sCli.PatchService(ctx, serviceName, labels, labelSelectors, portsTCP, portsUDP)
service, err := i.K8sClient.PatchService(ctx, serviceName, labels, labelSelectors, portsTCP, portsUDP)
if err != nil {
return ErrPatchingService.WithParams(serviceName).Wrap(err)
}
Expand All @@ -122,7 +122,7 @@ func (i *Instance) patchService(ctx context.Context, portsTCP, portsUDP []int) e

// destroyService destroys the service for the instance
func (i *Instance) destroyService(ctx context.Context) error {
return i.K8sCli.DeleteService(ctx, i.k8sName)
return i.K8sClient.DeleteService(ctx, i.k8sName)
}

// deployPod deploys the pod for the instance
Expand All @@ -131,24 +131,24 @@ func (i *Instance) deployPod(ctx context.Context) error {
labels := i.getLabels()

// create a service account for the pod
if err := i.K8sCli.CreateServiceAccount(ctx, i.k8sName, labels); err != nil {
if err := i.K8sClient.CreateServiceAccount(ctx, i.k8sName, labels); err != nil {
return ErrFailedToCreateServiceAccount.Wrap(err)
}

// create a role and role binding for the pod if there are policy rules
if len(i.policyRules) > 0 {
if err := i.K8sCli.CreateRole(ctx, i.k8sName, labels, i.policyRules); err != nil {
if err := i.K8sClient.CreateRole(ctx, i.k8sName, labels, i.policyRules); err != nil {
return ErrFailedToCreateRole.Wrap(err)
}
if err := i.K8sCli.CreateRoleBinding(ctx, i.k8sName, labels, i.k8sName, i.k8sName); err != nil {
if err := i.K8sClient.CreateRoleBinding(ctx, i.k8sName, labels, i.k8sName, i.k8sName); err != nil {
return ErrFailedToCreateRoleBinding.Wrap(err)
}
}

replicaSetSetConfig := i.prepareReplicaSetConfig()

// Deploy the statefulSet
replicaSet, err := i.K8sCli.CreateReplicaSet(ctx, replicaSetSetConfig, true)
replicaSet, err := i.K8sClient.CreateReplicaSet(ctx, replicaSetSetConfig, true)
if err != nil {
return ErrFailedToDeployPod.Wrap(err)
}
Expand All @@ -167,21 +167,21 @@ func (i *Instance) deployPod(ctx context.Context) error {
// Skips if the pod is already destroyed
func (i *Instance) destroyPod(ctx context.Context) error {
grace := int64(0)
err := i.K8sCli.DeleteReplicaSetWithGracePeriod(ctx, i.k8sName, &grace)
err := i.K8sClient.DeleteReplicaSetWithGracePeriod(ctx, i.k8sName, &grace)
if err != nil {
return ErrFailedToDeletePod.Wrap(err)
}

// Delete the service account for the pod
if err := i.K8sCli.DeleteServiceAccount(ctx, i.k8sName); err != nil {
if err := i.K8sClient.DeleteServiceAccount(ctx, i.k8sName); err != nil {
return ErrFailedToDeleteServiceAccount.Wrap(err)
}
// Delete the role and role binding for the pod if there are policy rules
if len(i.policyRules) > 0 {
if err := i.K8sCli.DeleteRole(ctx, i.k8sName); err != nil {
if err := i.K8sClient.DeleteRole(ctx, i.k8sName); err != nil {
return ErrFailedToDeleteRole.Wrap(err)
}
if err := i.K8sCli.DeleteRoleBinding(ctx, i.k8sName); err != nil {
if err := i.K8sClient.DeleteRoleBinding(ctx, i.k8sName); err != nil {
return ErrFailedToDeleteRoleBinding.Wrap(err)
}
}
Expand All @@ -193,7 +193,7 @@ func (i *Instance) destroyPod(ctx context.Context) error {
func (i *Instance) deployOrPatchService(ctx context.Context, portsTCP, portsUDP []int) error {
if len(portsTCP) != 0 || len(portsUDP) != 0 {
logrus.Debugf("Ports not empty, deploying service for instance '%s'", i.k8sName)
svc, _ := i.K8sCli.GetService(ctx, i.k8sName)
svc, _ := i.K8sClient.GetService(ctx, i.k8sName)
if svc == nil {
err := i.deployService(ctx, portsTCP, portsUDP)
if err != nil {
Expand All @@ -215,15 +215,15 @@ func (i *Instance) deployVolume(ctx context.Context) error {
for _, volume := range i.volumes {
size.Add(resource.MustParse(volume.Size))
}
i.K8sCli.CreatePersistentVolumeClaim(ctx, i.k8sName, i.getLabels(), size)
i.K8sClient.CreatePersistentVolumeClaim(ctx, i.k8sName, i.getLabels(), size)
logrus.Debugf("Deployed persistent volume '%s'", i.k8sName)

return nil
}

// destroyVolume destroys the volume for the instance
func (i *Instance) destroyVolume(ctx context.Context) error {
i.K8sCli.DeletePersistentVolumeClaim(ctx, i.k8sName)
i.K8sClient.DeletePersistentVolumeClaim(ctx, i.k8sName)
logrus.Debugf("Destroyed persistent volume '%s'", i.k8sName)

return nil
Expand Down Expand Up @@ -256,7 +256,7 @@ func (i *Instance) deployFiles(ctx context.Context) error {
}

// create configmap
if _, err := i.K8sCli.CreateConfigMap(ctx, i.k8sName, i.getLabels(), data); err != nil {
if _, err := i.K8sClient.CreateConfigMap(ctx, i.k8sName, i.getLabels(), data); err != nil {
return ErrFailedToCreateConfigMap.Wrap(err)
}

Expand All @@ -267,7 +267,7 @@ func (i *Instance) deployFiles(ctx context.Context) error {

// destroyFiles destroys the files for the instance
func (i *Instance) destroyFiles(ctx context.Context) error {
if err := i.K8sCli.DeleteConfigMap(ctx, i.k8sName); err != nil {
if err := i.K8sClient.DeleteConfigMap(ctx, i.k8sName); err != nil {
return ErrFailedToDeleteConfigMap.Wrap(err)
}

Expand Down Expand Up @@ -508,7 +508,7 @@ func (i *Instance) prepareReplicaSetConfig() k8s.ReplicaSetConfig {
}
// Generate the pod configuration
podConfig := k8s.PodConfig{
Namespace: i.K8sCli.Namespace(),
Namespace: i.K8sClient.Namespace(),
Name: i.k8sName,
Labels: i.getLabels(),
ServiceAccountName: i.k8sName,
Expand All @@ -518,7 +518,7 @@ func (i *Instance) prepareReplicaSetConfig() k8s.ReplicaSetConfig {
}
// Generate the ReplicaSet configuration
statefulSetConfig := k8s.ReplicaSetConfig{
Namespace: i.K8sCli.Namespace(),
Namespace: i.K8sClient.Namespace(),
Name: i.k8sName,
Labels: i.getLabels(),
Replicas: 1,
Expand All @@ -535,7 +535,7 @@ func (i *Instance) setImageWithGracePeriod(ctx context.Context, imageName string
replicaSetConfig := i.prepareReplicaSetConfig()

// Replace the pod with a new one, using the given image
_, err := i.K8sCli.ReplaceReplicaSetWithGracePeriod(ctx, replicaSetConfig, gracePeriod)
_, err := i.K8sClient.ReplaceReplicaSetWithGracePeriod(ctx, replicaSetConfig, gracePeriod)
if err != nil {
return ErrReplacingPod.Wrap(err)
}
Expand Down
Loading
Loading