diff --git a/pkg/resources/k8sgpt.go b/pkg/resources/k8sgpt.go index 327a3814..780240af 100644 --- a/pkg/resources/k8sgpt.go +++ b/pkg/resources/k8sgpt.go @@ -23,7 +23,6 @@ import ( "github.com/k8sgpt-ai/k8sgpt-operator/pkg/utils" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" r1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" @@ -290,7 +289,7 @@ func GetDeployment(config v1alpha1.K8sGPT, outOfClusterMode bool) (*appsv1.Deplo }) deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, corev1.Volume{ Name: "kubeconfig", - VolumeSource: v1.VolumeSource{ + VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ SecretName: config.Spec.Kubeconfig.Name, Items: []corev1.KeyToPath{ @@ -323,11 +322,11 @@ func GetDeployment(config v1alpha1.K8sGPT, outOfClusterMode bool) (*appsv1.Deplo // check to see if key/value exists addRemoteCacheEnvVar := func(name, key string) { - envVar := v1.EnvVar{ + envVar := corev1.EnvVar{ Name: name, - ValueFrom: &v1.EnvVarSource{ - SecretKeyRef: &v1.SecretKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ Name: config.Spec.RemoteCache.Credentials.Name, }, Key: key, diff --git a/pkg/resources/k8sgpt_test.go b/pkg/resources/k8sgpt_test.go index 205c1ebe..074b8a26 100644 --- a/pkg/resources/k8sgpt_test.go +++ b/pkg/resources/k8sgpt_test.go @@ -4,17 +4,229 @@ import ( "context" "testing" + "github.com/k8sgpt-ai/k8sgpt-operator/api/v1alpha1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" + + rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + + clientgoscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" ) +func Test_GetService(t *testing.T) { + // Create a K8sGPT object + config := v1alpha1.K8sGPT{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + UID: "12345", + }, + } + + // Call GetService + service, err := GetService(config) + assert.NoError(t, err) + + // Check the service's properties + assert.Equal(t, config.Name, service.Name) + assert.Equal(t, config.Namespace, service.Namespace) + assert.Equal(t, config.Name, service.OwnerReferences[0].Name) + assert.Equal(t, int32(8080), service.Spec.Ports[0].Port) +} + +func Test_GetServiceAccount(t *testing.T) { + // Create a K8sGPT object + config := v1alpha1.K8sGPT{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + UID: "12345", + }, + Spec: v1alpha1.K8sGPTSpec{ + ImagePullSecrets: []v1alpha1.ImagePullSecrets{ + {Name: "secret1"}, + {Name: "secret2"}, + }, + }, + } + + // Call GetServiceAccount + serviceAccount, err := GetServiceAccount(config) + assert.NoError(t, err) + + // Check the service account's properties + assert.Equal(t, "k8sgpt", serviceAccount.Name) + assert.Equal(t, config.Namespace, serviceAccount.Namespace) + assert.Equal(t, "secret1", serviceAccount.ImagePullSecrets[0].Name) + assert.Equal(t, "secret2", serviceAccount.ImagePullSecrets[1].Name) +} + +func Test_GetClusterRoleBinding(t *testing.T) { + // Create a K8sGPT object + config := v1alpha1.K8sGPT{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + UID: "12345", + }, + } + + // Call GetClusterRoleBinding + clusterRoleBinding, err := GetClusterRoleBinding(config) + assert.NoError(t, err) + + // Check the cluster role binding's properties + assert.Equal(t, "k8sgpt", clusterRoleBinding.Name) + assert.Equal(t, config.UID, clusterRoleBinding.OwnerReferences[0].UID) + assert.Equal(t, "ServiceAccount", clusterRoleBinding.Subjects[0].Kind) + assert.Equal(t, "k8sgpt", clusterRoleBinding.Subjects[0].Name) + assert.Equal(t, config.Namespace, clusterRoleBinding.Subjects[0].Namespace) + assert.Equal(t, "ClusterRole", clusterRoleBinding.RoleRef.Kind) + assert.Equal(t, "k8sgpt", clusterRoleBinding.RoleRef.Name) + assert.Equal(t, "rbac.authorization.k8s.io", clusterRoleBinding.RoleRef.APIGroup) +} + +func Test_GetClusterRole(t *testing.T) { + // Create a K8sGPT object + config := v1alpha1.K8sGPT{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + UID: "12345", + }, + } + + // Call GetClusterRole + clusterRole, err := GetClusterRole(config) + assert.NoError(t, err) + + // Check the cluster role's properties + assert.Equal(t, "k8sgpt", clusterRole.Name) + assert.Equal(t, config.Name, clusterRole.OwnerReferences[0].Name) + assert.Equal(t, config.UID, clusterRole.OwnerReferences[0].UID) + assert.Equal(t, config.APIVersion, clusterRole.OwnerReferences[0].APIVersion) + assert.Contains(t, clusterRole.Rules[0].APIGroups, "*") + assert.Contains(t, clusterRole.Rules[0].Resources, "*") + assert.ElementsMatch(t, clusterRole.Rules[0].Verbs, []string{"create", "list", "get", "watch", "delete"}) + assert.Contains(t, clusterRole.Rules[1].APIGroups, "apiextensions.k8s.io") + assert.Contains(t, clusterRole.Rules[1].Resources, "*") + assert.Contains(t, clusterRole.Rules[1].Verbs, "*") +} + +func Test_GetDeployment(t *testing.T) { + // Create a K8sGPT object + config := v1alpha1.K8sGPT{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: v1alpha1.K8sGPTSpec{ + Repository: "repo", + Version: "1.0", + AI: &v1alpha1.AISpec{ + Model: "model", + Backend: "azureopenai", + Secret: &v1alpha1.SecretRef{ + Name: "secret", + Key: "key", + }, + BaseUrl: "http://baseurl", + Engine: "engine", + }, + Kubeconfig: &v1alpha1.SecretRef{ + Name: "kubeconfig", + Key: "key", + }, + RemoteCache: &v1alpha1.RemoteCacheRef{ + Credentials: &v1alpha1.CredentialsRef{ + Name: "credentials", + }, + Azure: &v1alpha1.AzureBackend{}, + }, + NodeSelector: map[string]string{ + "node": "node1", + }, + }, + } + + // Call GetDeployment + deployment, err := GetDeployment(config, true) + assert.NoError(t, err) + + // Check that the deployment has the expected properties + assert.Equal(t, "test", deployment.Name) + assert.Equal(t, "default", deployment.Namespace) + assert.Equal(t, "repo:1.0", deployment.Spec.Template.Spec.Containers[0].Image) + assert.Equal(t, "model", deployment.Spec.Template.Spec.Containers[0].Env[0].Value) + assert.Equal(t, "azureopenai", deployment.Spec.Template.Spec.Containers[0].Env[1].Value) + assert.Equal(t, "secret", deployment.Spec.Template.Spec.Containers[0].Env[4].ValueFrom.SecretKeyRef.LocalObjectReference.Name) + assert.Equal(t, "key", deployment.Spec.Template.Spec.Containers[0].Env[4].ValueFrom.SecretKeyRef.Key) + assert.Equal(t, "credentials", deployment.Spec.Template.Spec.Containers[0].Env[7].ValueFrom.SecretKeyRef.LocalObjectReference.Name) + assert.Equal(t, "azure_client_secret", deployment.Spec.Template.Spec.Containers[0].Env[7].ValueFrom.SecretKeyRef.Key) + assert.Equal(t, "kubeconfig", deployment.Spec.Template.Spec.Volumes[1].Name) + assert.Equal(t, "kubeconfig", deployment.Spec.Template.Spec.Volumes[1].VolumeSource.Secret.SecretName) + assert.Equal(t, "key", deployment.Spec.Template.Spec.Volumes[1].VolumeSource.Secret.Items[0].Key) + assert.Equal(t, "kubeconfig", deployment.Spec.Template.Spec.Volumes[1].VolumeSource.Secret.Items[0].Path) + assert.Equal(t, "", deployment.Spec.Template.Spec.ServiceAccountName) + assert.Equal(t, false, *deployment.Spec.Template.Spec.AutomountServiceAccountToken) +} + +func Test_Sync(t *testing.T) { + // Create a fake client + scheme := runtime.NewScheme() + _ = clientgoscheme.AddToScheme(scheme) + _ = v1alpha1.AddToScheme(scheme) + c := fake.NewFakeClientWithScheme(scheme) + + // Create a K8sGPT object + config := v1alpha1.K8sGPT{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: v1alpha1.K8sGPTSpec{ + Repository: "repo", + Version: "1.0", + AI: &v1alpha1.AISpec{ + Model: "model", + Backend: "backend", + }, + }, + } + + // Call Sync + err := Sync(context.Background(), c, config, SyncOp) + assert.NoError(t, err) + + // Check that the expected objects were created + svcAcc := &v1.ServiceAccount{} + err = c.Get(context.Background(), client.ObjectKey{Name: "k8sgpt", Namespace: "default"}, svcAcc) + assert.NoError(t, err) + + clusterRole := &rbacv1.ClusterRole{} + err = c.Get(context.Background(), client.ObjectKey{Name: "k8sgpt"}, clusterRole) + assert.NoError(t, err) + + clusterRoleBinding := &rbacv1.ClusterRoleBinding{} + err = c.Get(context.Background(), client.ObjectKey{Name: "k8sgpt"}, clusterRoleBinding) + assert.NoError(t, err) + + svc := &v1.Service{} + err = c.Get(context.Background(), client.ObjectKey{Name: "test", Namespace: "default"}, svc) + assert.NoError(t, err) + + deployment := &appsv1.Deployment{} + err = c.Get(context.Background(), client.ObjectKey{Name: "test", Namespace: "default"}, deployment) + assert.NoError(t, err) +} + func Test_DeploymentShouldBeSynced(t *testing.T) { scheme := runtime.NewScheme() require.NoError(t, appsv1.AddToScheme(scheme)) diff --git a/pkg/resources/result_test.go b/pkg/resources/result_test.go new file mode 100644 index 00000000..7cbdec91 --- /dev/null +++ b/pkg/resources/result_test.go @@ -0,0 +1,88 @@ +package resources + +import ( + "context" + "testing" + + "github.com/k8sgpt-ai/k8sgpt-operator/api/v1alpha1" + "github.com/k8sgpt-ai/k8sgpt-operator/pkg/integrations" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kubectl/pkg/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func Test_MapResults(t *testing.T) { + // Create a K8sGPT object + config := v1alpha1.K8sGPT{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Spec: v1alpha1.K8sGPTSpec{ + AI: &v1alpha1.AISpec{ + Backend: "backend", + }, + ExtraOptions: &v1alpha1.ExtraOptionsRef{ + Backstage: &v1alpha1.Backstage{ + Enabled: true, + }, + }, + }, + } + + // Create a ResultSpec slice + resultsSpec := []v1alpha1.ResultSpec{ + { + Name: "result-1", + }, + { + Name: "result-2", + }, + } + + c := fake.NewFakeClient() + + // Create an Integrations object + i, err := integrations.NewIntegrations(c, context.Background()) + assert.NoError(t, err) + + // Call MapResults + results, err := MapResults(*i, resultsSpec, config) + assert.NoError(t, err) + + // Check that the expected results were returned + assert.Equal(t, 2, len(results)) + assert.Contains(t, results, "result1") + assert.Contains(t, results, "result2") +} + +func Test_CreateOrUpdateResult(t *testing.T) { + // Create a fake client + s := scheme.Scheme + s.AddKnownTypes(v1alpha1.GroupVersion, &v1alpha1.Result{}) + cl := fake.NewFakeClientWithScheme(s) + + // Create a new result object + res := &v1alpha1.Result{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "test": "test", + }, + Name: "test", + Namespace: "default", + }, + Spec: v1alpha1.ResultSpec{ + Error: []v1alpha1.Failure{ + { + Text: "error", + }, + }, + }, + } + + // Test creating a new result + op, err := CreateOrUpdateResult(context.Background(), cl, *res) + assert.NoError(t, err) + assert.Equal(t, CreatedResult, op) +} \ No newline at end of file diff --git a/pkg/resources/results.go b/pkg/resources/results.go index bb4cab01..3c594f2f 100644 --- a/pkg/resources/results.go +++ b/pkg/resources/results.go @@ -17,8 +17,8 @@ type ResultOperation string const ( CreatedResult ResultOperation = "created" - UpdatedResult = "updated" - NoOpResult = "historical" + UpdatedResult ResultOperation = "updated" + NoOpResult ResultOperation = "historical" ) func MapResults(i integrations.Integrations, resultsSpec []v1alpha1.ResultSpec, config v1alpha1.K8sGPT) (map[string]v1alpha1.Result, error) {