From cbdf03dbc42100343bdd51b680e92398a8a60dbd Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:42:05 -0700 Subject: [PATCH 01/12] Added new e2e test case to do the remote registry deployment. abstracted the code to do the featurestore testing. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- infra/feast-operator/test/e2e/e2e_test.go | 218 +++++++++++++----- infra/feast-operator/test/e2e/test_util.go | 43 ++++ ...v1alpha1_remote_registry_featurestore.yaml | 15 ++ 3 files changed, 222 insertions(+), 54 deletions(-) create mode 100644 infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml diff --git a/infra/feast-operator/test/e2e/e2e_test.go b/infra/feast-operator/test/e2e/e2e_test.go index 7d9fb9af056..fdf8d31b7f3 100644 --- a/infra/feast-operator/test/e2e/e2e_test.go +++ b/infra/feast-operator/test/e2e/e2e_test.go @@ -57,10 +57,10 @@ var _ = Describe("controller", Ordered, func() { err = utils.LoadImageToKindClusterWithName(projectimage) ExpectWithOffset(1, err).NotTo(HaveOccurred()) - By("building the feast image") - cmd = exec.Command("make", "feast-ci-dev-docker-img") - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) + //By("building the feast image") + //cmd = exec.Command("make", "feast-ci-dev-docker-img") + //_, err = utils.Run(cmd) + //ExpectWithOffset(1, err).NotTo(HaveOccurred()) // this image will be built in above make target. var feastImage = "feastdev/feature-server:dev" var feastLocalImage = "localhost/feastdev/feature-server:dev" @@ -102,59 +102,101 @@ var _ = Describe("controller", Ordered, func() { ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) namespace := "default" + featureStoreName := "simple-feast-setup" - deploymentNames := [3]string{"feast-simple-feast-setup-registry", "feast-simple-feast-setup-online", - "feast-simple-feast-setup-offline"} - for _, deploymentName := range deploymentNames { - By(fmt.Sprintf("validate the feast deployment: %s is up and in availability state.", deploymentName)) - err = checkIfDeploymentExistsAndAvailable(namespace, deploymentName, timeout) - Expect(err).To(BeNil(), fmt.Sprintf( - "Deployment %s is not available but expected to be available. \nError: %v\n", - deploymentName, err, - )) - fmt.Printf("Feast Deployment %s is available\n", deploymentName) - } - - By("Check if the feast client - kubernetes config map exists.") - configMapName := "feast-simple-feast-setup-client" - err = checkIfConfigMapExists(namespace, configMapName) - Expect(err).To(BeNil(), fmt.Sprintf( - "config map %s is not available but expected to be available. \nError: %v\n", - configMapName, err, - )) - fmt.Printf("Feast Deployment %s is available\n", configMapName) - - serviceAccountNames := [3]string{"feast-simple-feast-setup-registry", "feast-simple-feast-setup-online", - "feast-simple-feast-setup-offline"} - for _, serviceAccountName := range serviceAccountNames { - By(fmt.Sprintf("validate the feast service account: %s is available.", serviceAccountName)) - err = checkIfServiceAccountExists(namespace, serviceAccountName) - Expect(err).To(BeNil(), fmt.Sprintf( - "Service account %s does not exist in namespace %s. Error: %v", - serviceAccountName, namespace, err, - )) - fmt.Printf("Service account %s exists in namespace %s\n", serviceAccountName, namespace) - } - - serviceNames := [3]string{"feast-simple-feast-setup-registry", "feast-simple-feast-setup-online", - "feast-simple-feast-setup-offline"} - for _, serviceName := range serviceNames { - By(fmt.Sprintf("validate the kubernetes service name: %s is available.", serviceName)) - err = checkIfKubernetesServiceExists(namespace, serviceName) - Expect(err).To(BeNil(), fmt.Sprintf( - "kubernetes service %s is not available but expected to be available. \nError: %v\n", - serviceName, err, - )) - fmt.Printf("kubernetes service %s is available\n", serviceName) - } - - By(fmt.Sprintf("Checking FeatureStore customer resource: %s is in Ready Status.", "simple-feast-setup")) - err = checkIfFeatureStoreCustomResourceConditionsInReady("simple-feast-setup", namespace) + validateTheFeatureStore(namespace, featureStoreName, timeout) + + By("deleting the feast deployment") + cmd = exec.Command("kubectl", "delete", "-f", + "test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml") + _, cmdOutputerr = utils.Run(cmd) + ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) + + By("Uninstalling the feast CRD") + cmd = exec.Command("kubectl", "delete", "deployment", controllerDeploymentName, "-n", feastControllerNamespace) + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + }) + + It("Should be able to deploy and run a remote feature store CR successfully", func() { + //var controllerPodName string + var err error + + // projectimage stores the name of the image used in the example + var projectimage = "localhost/feast-operator:v0.0.1" + + By("building the manager(Operator) image") + cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectimage)) + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + By("loading the the manager(Operator) image on Kind") + err = utils.LoadImageToKindClusterWithName(projectimage) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + //By("building the feast image") + //cmd = exec.Command("make", "feast-ci-dev-docker-img") + //_, err = utils.Run(cmd) + //ExpectWithOffset(1, err).NotTo(HaveOccurred()) + // this image will be built in above make target. + var feastImage = "feastdev/feature-server:dev" + var feastLocalImage = "localhost/feastdev/feature-server:dev" + + By("Tag the local feast image for the integration tests") + cmd = exec.Command("docker", "image", "tag", feastImage, feastLocalImage) + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + By("loading the the feast image on Kind cluster") + err = utils.LoadImageToKindClusterWithName(feastLocalImage) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + By("installing CRDs") + cmd = exec.Command("make", "install") + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + By("deploying the controller-manager") + cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectimage)) + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + timeout := 2 * time.Minute + + controllerDeploymentName := "feast-operator-controller-manager" + By("Validating that the controller-manager deployment is in available state") + err = checkIfDeploymentExistsAndAvailable(feastControllerNamespace, controllerDeploymentName, timeout) Expect(err).To(BeNil(), fmt.Sprintf( - "FeatureStore custom resource %s all conditions are not in ready state. \nError: %v\n", - "simple-feast-setup", err, + "Deployment %s is not available but expected to be available. \nError: %v\n", + controllerDeploymentName, err, )) - fmt.Printf("FeatureStore customer resource %s conditions are in Ready State\n", "simple-feast-setup") + fmt.Printf("Feast Control Manager Deployment %s is available\n", controllerDeploymentName) + + By("deploying the Simple Feast Custom Resource to Kubernetes") + cmd = exec.Command("kubectl", "apply", "-f", + "test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml") + _, cmdOutputerr := utils.Run(cmd) + ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) + + namespace := "default" + featureStoreName := "simple-feast-setup" + + validateTheFeatureStore(namespace, featureStoreName, timeout) + + var remoteRegistryNs = "remote-registry" + cmd = exec.Command("kubectl", "create", "ns", remoteRegistryNs) + _, _ = utils.Run(cmd) + + By("deploying the Simple Feast remote registry Custom Resource to Kubernetes") + cmd = exec.Command("kubectl", "apply", "-f", + "test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml", "-n", remoteRegistryNs) + _, cmdOutputerr = utils.Run(cmd) + ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) + + remoteFeatureStoreName := "simple-feast-remote-setup" + + validateTheFeatureStore(remoteRegistryNs, remoteFeatureStoreName, timeout) By("deleting the feast deployment") cmd = exec.Command("kubectl", "delete", "-f", @@ -162,6 +204,12 @@ var _ = Describe("controller", Ordered, func() { _, cmdOutputerr = utils.Run(cmd) ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) + By("deleting the feast remote registry deployment") + cmd = exec.Command("kubectl", "delete", "-f", + "test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml", "-n", remoteRegistryNs) + _, cmdOutputerr = utils.Run(cmd) + ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) + By("Uninstalling the feast CRD") cmd = exec.Command("kubectl", "delete", "deployment", controllerDeploymentName, "-n", feastControllerNamespace) _, err = utils.Run(cmd) @@ -170,3 +218,65 @@ var _ = Describe("controller", Ordered, func() { }) }) }) + +func validateTheFeatureStore(namespace string, featureStoreName string, timeout time.Duration) { + hasRemoteRegistry, err := isFeatureStoreHavingRemoteRegistry(namespace, featureStoreName) + Expect(err).To(BeNil(), fmt.Sprintf( + "Error occurred while FeatureStore %s is having remote registry or not. \nError: %v\n", + featureStoreName, err)) + + k8ResourceNames := []string{fmt.Sprintf("feast-%s-online", featureStoreName), + fmt.Sprintf("feast-%s-offline", featureStoreName), + } + + if !hasRemoteRegistry { + k8ResourceNames = append(k8ResourceNames, fmt.Sprintf("feast-%s-registry", featureStoreName)) + } + + for _, deploymentName := range k8ResourceNames { + By(fmt.Sprintf("validate the feast deployment: %s is up and in availability state.", deploymentName)) + err = checkIfDeploymentExistsAndAvailable(namespace, deploymentName, timeout) + Expect(err).To(BeNil(), fmt.Sprintf( + "Deployment %s is not available but expected to be available. \nError: %v\n", + deploymentName, err, + )) + fmt.Printf("Feast Deployment %s is available\n", deploymentName) + } + + By("Check if the feast client - kubernetes config map exists.") + configMapName := fmt.Sprintf("feast-%s-client", featureStoreName) + err = checkIfConfigMapExists(namespace, configMapName) + Expect(err).To(BeNil(), fmt.Sprintf( + "config map %s is not available but expected to be available. \nError: %v\n", + configMapName, err, + )) + fmt.Printf("Feast Deployment client config map %s is available\n", configMapName) + + for _, serviceAccountName := range k8ResourceNames { + By(fmt.Sprintf("validate the feast service account: %s is available.", serviceAccountName)) + err = checkIfServiceAccountExists(namespace, serviceAccountName) + Expect(err).To(BeNil(), fmt.Sprintf( + "Service account %s does not exist in namespace %s. Error: %v", + serviceAccountName, namespace, err, + )) + fmt.Printf("Service account %s exists in namespace %s\n", serviceAccountName, namespace) + } + + for _, serviceName := range k8ResourceNames { + By(fmt.Sprintf("validate the kubernetes service name: %s is available.", serviceName)) + err = checkIfKubernetesServiceExists(namespace, serviceName) + Expect(err).To(BeNil(), fmt.Sprintf( + "kubernetes service %s is not available but expected to be available. \nError: %v\n", + serviceName, err, + )) + fmt.Printf("kubernetes service %s is available\n", serviceName) + } + + By(fmt.Sprintf("Checking FeatureStore customer resource: %s is in Ready Status.", featureStoreName)) + err = checkIfFeatureStoreCustomResourceConditionsInReady(featureStoreName, namespace) + Expect(err).To(BeNil(), fmt.Sprintf( + "FeatureStore custom resource %s all conditions are not in ready state. \nError: %v\n", + featureStoreName, err, + )) + fmt.Printf("FeatureStore customer resource %s conditions are in Ready State\n", featureStoreName) +} diff --git a/infra/feast-operator/test/e2e/test_util.go b/infra/feast-operator/test/e2e/test_util.go index f30d8cbebf5..2417084c141 100644 --- a/infra/feast-operator/test/e2e/test_util.go +++ b/infra/feast-operator/test/e2e/test_util.go @@ -3,6 +3,7 @@ package e2e import ( "bytes" "encoding/json" + "errors" "fmt" "os/exec" "strings" @@ -184,3 +185,45 @@ func checkIfKubernetesServiceExists(namespace, serviceName string) error { return nil } + +func isFeatureStoreHavingRemoteRegistry(namespace, featureStoreName string) (bool, error) { + cmd := exec.Command("kubectl", "get", "featurestore", featureStoreName, "-n", namespace, + "-o=jsonpath='{.spec.services.registry}'") + + // Capture the output + output, err := cmd.Output() + if err != nil { + return false, err // Return false on command execution failure + } + + // Convert output to string and trim any extra spaces + result := strings.TrimSpace(string(output)) + + // Remove single quotes if present + if strings.HasPrefix(result, "'") && strings.HasSuffix(result, "'") { + result = strings.Trim(result, "'") + } + + if result == "" { + return false, errors.New("kubectl get featurestore command returned empty output") + } + + // Parse the JSON into a map + var registryData map[string]interface{} + if err := json.Unmarshal([]byte(result), ®istryData); err != nil { + return false, err // Return false on JSON parsing failure + } + + // Navigate the map to check for the "remote.hostname" field + remote, ok := registryData["remote"].(map[string]interface{}) + if !ok { + return false, nil // Return false if "remote" is not present + } + + hostname, ok := remote["hostname"].(string) + if !ok || hostname == "" { + return false, nil // Return false if "hostname" is missing or empty + } + + return true, nil // Return true if "remote.hostname" exists and has a value +} diff --git a/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml b/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml new file mode 100644 index 00000000000..2d47e6c44eb --- /dev/null +++ b/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml @@ -0,0 +1,15 @@ +apiVersion: feast.dev/v1alpha1 +kind: FeatureStore +metadata: + name: simple-feast-remote-setup +spec: + feastProject: my_project + services: + onlineStore: + image: 'localhost/feastdev/feature-server:dev' + offlineStore: + image: 'localhost/feastdev/feature-server:dev' + registry: + remote: + hostname: 'feast-simple-feast-setup-registry.default.svc.cluster.local:80' + From c861b91f9f55dea78b4b26ecc86e229b38672708 Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Thu, 5 Dec 2024 23:18:40 -0700 Subject: [PATCH 02/12] abstracted the code even further. Now the custom resource CR will execute only once for all the test cases. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- infra/feast-operator/test/e2e/e2e_test.go | 209 ++++++++-------------- 1 file changed, 71 insertions(+), 138 deletions(-) diff --git a/infra/feast-operator/test/e2e/e2e_test.go b/infra/feast-operator/test/e2e/e2e_test.go index fdf8d31b7f3..00c10b89e68 100644 --- a/infra/feast-operator/test/e2e/e2e_test.go +++ b/infra/feast-operator/test/e2e/e2e_test.go @@ -28,161 +28,100 @@ import ( ) const feastControllerNamespace = "feast-operator-system" +const timeout = 2 * time.Minute +const controllerDeploymentName = "feast-operator-controller-manager" var _ = Describe("controller", Ordered, func() { BeforeAll(func() { By("creating manager namespace") cmd := exec.Command("kubectl", "create", "ns", feastControllerNamespace) _, _ = utils.Run(cmd) + var err error + // projectimage stores the name of the image used in the example + var projectimage = "localhost/feast-operator:v0.0.1" + + By("building the manager(Operator) image") + cmd = exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectimage)) + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + By("loading the the manager(Operator) image on Kind") + err = utils.LoadImageToKindClusterWithName(projectimage) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + //By("building the feast image") + //cmd = exec.Command("make", "feast-ci-dev-docker-img") + //_, err = utils.Run(cmd) + //ExpectWithOffset(1, err).NotTo(HaveOccurred()) + // this image will be built in above make target. + var feastImage = "feastdev/feature-server:dev" + var feastLocalImage = "localhost/feastdev/feature-server:dev" + + By("Tag the local feast image for the integration tests") + cmd = exec.Command("docker", "image", "tag", feastImage, feastLocalImage) + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + By("loading the the feast image on Kind cluster") + err = utils.LoadImageToKindClusterWithName(feastLocalImage) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + By("installing CRDs") + cmd = exec.Command("make", "install") + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + By("deploying the controller-manager") + cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectimage)) + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + By("Validating that the controller-manager deployment is in available state") + err = checkIfDeploymentExistsAndAvailable(feastControllerNamespace, controllerDeploymentName, timeout) + Expect(err).To(BeNil(), fmt.Sprintf( + "Deployment %s is not available but expected to be available. \nError: %v\n", + controllerDeploymentName, err, + )) + fmt.Printf("Feast Control Manager Deployment %s is available\n", controllerDeploymentName) }) AfterAll(func() { //Add any post clean up code here. + By("Uninstalling the feast CRD") + cmd := exec.Command("kubectl", "delete", "deployment", controllerDeploymentName, "-n", feastControllerNamespace) + _, err := utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) }) - Context("Operator", func() { + Context("Operator E2E Tests", func() { It("Should be able to deploy and run a default feature store CR successfully", func() { - //var controllerPodName string - var err error - - // projectimage stores the name of the image used in the example - var projectimage = "localhost/feast-operator:v0.0.1" - - By("building the manager(Operator) image") - cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectimage)) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("loading the the manager(Operator) image on Kind") - err = utils.LoadImageToKindClusterWithName(projectimage) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - //By("building the feast image") - //cmd = exec.Command("make", "feast-ci-dev-docker-img") - //_, err = utils.Run(cmd) - //ExpectWithOffset(1, err).NotTo(HaveOccurred()) - // this image will be built in above make target. - var feastImage = "feastdev/feature-server:dev" - var feastLocalImage = "localhost/feastdev/feature-server:dev" - - By("Tag the local feast image for the integration tests") - cmd = exec.Command("docker", "image", "tag", feastImage, feastLocalImage) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("loading the the feast image on Kind cluster") - err = utils.LoadImageToKindClusterWithName(feastLocalImage) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("installing CRDs") - cmd = exec.Command("make", "install") - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("deploying the controller-manager") - cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectimage)) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - timeout := 2 * time.Minute - - controllerDeploymentName := "feast-operator-controller-manager" - By("Validating that the controller-manager deployment is in available state") - err = checkIfDeploymentExistsAndAvailable(feastControllerNamespace, controllerDeploymentName, timeout) - Expect(err).To(BeNil(), fmt.Sprintf( - "Deployment %s is not available but expected to be available. \nError: %v\n", - controllerDeploymentName, err, - )) - fmt.Printf("Feast Control Manager Deployment %s is available\n", controllerDeploymentName) - By("deploying the Simple Feast Custom Resource to Kubernetes") - cmd = exec.Command("kubectl", "apply", "-f", - "test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml") + namespace := "default" + cmd := exec.Command("kubectl", "apply", "-f", + "test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml", "-n", namespace) _, cmdOutputerr := utils.Run(cmd) ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) - namespace := "default" featureStoreName := "simple-feast-setup" - - validateTheFeatureStore(namespace, featureStoreName, timeout) + validateTheFeatureStoreCustomResource(namespace, featureStoreName, timeout) By("deleting the feast deployment") cmd = exec.Command("kubectl", "delete", "-f", "test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml") _, cmdOutputerr = utils.Run(cmd) ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) - - By("Uninstalling the feast CRD") - cmd = exec.Command("kubectl", "delete", "deployment", controllerDeploymentName, "-n", feastControllerNamespace) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - }) - It("Should be able to deploy and run a remote feature store CR successfully", func() { - //var controllerPodName string - var err error - - // projectimage stores the name of the image used in the example - var projectimage = "localhost/feast-operator:v0.0.1" - - By("building the manager(Operator) image") - cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectimage)) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("loading the the manager(Operator) image on Kind") - err = utils.LoadImageToKindClusterWithName(projectimage) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - //By("building the feast image") - //cmd = exec.Command("make", "feast-ci-dev-docker-img") - //_, err = utils.Run(cmd) - //ExpectWithOffset(1, err).NotTo(HaveOccurred()) - // this image will be built in above make target. - var feastImage = "feastdev/feature-server:dev" - var feastLocalImage = "localhost/feastdev/feature-server:dev" - - By("Tag the local feast image for the integration tests") - cmd = exec.Command("docker", "image", "tag", feastImage, feastLocalImage) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("loading the the feast image on Kind cluster") - err = utils.LoadImageToKindClusterWithName(feastLocalImage) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("installing CRDs") - cmd = exec.Command("make", "install") - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("deploying the controller-manager") - cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectimage)) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - timeout := 2 * time.Minute - - controllerDeploymentName := "feast-operator-controller-manager" - By("Validating that the controller-manager deployment is in available state") - err = checkIfDeploymentExistsAndAvailable(feastControllerNamespace, controllerDeploymentName, timeout) - Expect(err).To(BeNil(), fmt.Sprintf( - "Deployment %s is not available but expected to be available. \nError: %v\n", - controllerDeploymentName, err, - )) - fmt.Printf("Feast Control Manager Deployment %s is available\n", controllerDeploymentName) - + It("Should be able to deploy and run a feature store with remote registry CR successfully", func() { By("deploying the Simple Feast Custom Resource to Kubernetes") - cmd = exec.Command("kubectl", "apply", "-f", - "test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml") + namespace := "default" + cmd := exec.Command("kubectl", "apply", "-f", + "test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml", "-n", namespace) _, cmdOutputerr := utils.Run(cmd) ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) - namespace := "default" featureStoreName := "simple-feast-setup" - - validateTheFeatureStore(namespace, featureStoreName, timeout) + validateTheFeatureStoreCustomResource(namespace, featureStoreName, timeout) var remoteRegistryNs = "remote-registry" cmd = exec.Command("kubectl", "create", "ns", remoteRegistryNs) @@ -196,33 +135,27 @@ var _ = Describe("controller", Ordered, func() { remoteFeatureStoreName := "simple-feast-remote-setup" - validateTheFeatureStore(remoteRegistryNs, remoteFeatureStoreName, timeout) + validateTheFeatureStoreCustomResource(remoteRegistryNs, remoteFeatureStoreName, timeout) - By("deleting the feast deployment") + By("deleting the feast remote registry deployment") cmd = exec.Command("kubectl", "delete", "-f", - "test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml") + "test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml", "-n", remoteRegistryNs) _, cmdOutputerr = utils.Run(cmd) ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) - By("deleting the feast remote registry deployment") + By("deleting the feast deployment") cmd = exec.Command("kubectl", "delete", "-f", - "test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml", "-n", remoteRegistryNs) + "test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml", "-n", namespace) _, cmdOutputerr = utils.Run(cmd) ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred()) - - By("Uninstalling the feast CRD") - cmd = exec.Command("kubectl", "delete", "deployment", controllerDeploymentName, "-n", feastControllerNamespace) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - }) }) }) -func validateTheFeatureStore(namespace string, featureStoreName string, timeout time.Duration) { +func validateTheFeatureStoreCustomResource(namespace string, featureStoreName string, timeout time.Duration) { hasRemoteRegistry, err := isFeatureStoreHavingRemoteRegistry(namespace, featureStoreName) Expect(err).To(BeNil(), fmt.Sprintf( - "Error occurred while FeatureStore %s is having remote registry or not. \nError: %v\n", + "Error occurred while checking FeatureStore %s is having remote registry or not. \nError: %v\n", featureStoreName, err)) k8ResourceNames := []string{fmt.Sprintf("feast-%s-online", featureStoreName), @@ -278,5 +211,5 @@ func validateTheFeatureStore(namespace string, featureStoreName string, timeout "FeatureStore custom resource %s all conditions are not in ready state. \nError: %v\n", featureStoreName, err, )) - fmt.Printf("FeatureStore customer resource %s conditions are in Ready State\n", featureStoreName) + fmt.Printf("FeatureStore custom resource %s conditions are in Ready State\n", featureStoreName) } From 8b52915cf6fd985781ba54681d221fef810d8df5 Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Thu, 5 Dec 2024 23:34:36 -0700 Subject: [PATCH 03/12] fixing the operator e2e test. this was commented before by mistake. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- infra/feast-operator/test/e2e/e2e_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/infra/feast-operator/test/e2e/e2e_test.go b/infra/feast-operator/test/e2e/e2e_test.go index 00c10b89e68..23637ff224b 100644 --- a/infra/feast-operator/test/e2e/e2e_test.go +++ b/infra/feast-operator/test/e2e/e2e_test.go @@ -49,10 +49,10 @@ var _ = Describe("controller", Ordered, func() { err = utils.LoadImageToKindClusterWithName(projectimage) ExpectWithOffset(1, err).NotTo(HaveOccurred()) - //By("building the feast image") - //cmd = exec.Command("make", "feast-ci-dev-docker-img") - //_, err = utils.Run(cmd) - //ExpectWithOffset(1, err).NotTo(HaveOccurred()) + By("building the feast image") + cmd = exec.Command("make", "feast-ci-dev-docker-img") + _, err = utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) // this image will be built in above make target. var feastImage = "feastdev/feature-server:dev" var feastLocalImage = "localhost/feastdev/feature-server:dev" From 0c32bf7d6a91dc777d9d007a91088b2d0f49ad6a Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Fri, 6 Dec 2024 00:12:26 -0700 Subject: [PATCH 04/12] increasing the remote registry deployment timeout to see if it solves the github CI timeout issue. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- infra/feast-operator/test/e2e/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/feast-operator/test/e2e/e2e_test.go b/infra/feast-operator/test/e2e/e2e_test.go index 23637ff224b..9f88b5e7ce8 100644 --- a/infra/feast-operator/test/e2e/e2e_test.go +++ b/infra/feast-operator/test/e2e/e2e_test.go @@ -135,7 +135,7 @@ var _ = Describe("controller", Ordered, func() { remoteFeatureStoreName := "simple-feast-remote-setup" - validateTheFeatureStoreCustomResource(remoteRegistryNs, remoteFeatureStoreName, timeout) + validateTheFeatureStoreCustomResource(remoteRegistryNs, remoteFeatureStoreName, 5*time.Minute) By("deleting the feast remote registry deployment") cmd = exec.Command("kubectl", "delete", "-f", From cd72ce1bbdae3819a2b80fb09a15079fecaaa858 Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:54:35 -0700 Subject: [PATCH 05/12] Trying to increase the timeout and also adding the debugging actions when there is a failure. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- .github/workflows/operator-e2e-integration-tests.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/operator-e2e-integration-tests.yml b/.github/workflows/operator-e2e-integration-tests.yml index 23c250cc535..1eeb3733976 100644 --- a/.github/workflows/operator-e2e-integration-tests.yml +++ b/.github/workflows/operator-e2e-integration-tests.yml @@ -13,6 +13,7 @@ on: jobs: operator-e2e-tests: + timeout-minutes: 40 if: ((github.event.action == 'labeled' && (github.event.label.name == 'approved' || github.event.label.name == 'lgtm' || github.event.label.name == 'ok-to-test')) || (github.event.action != 'labeled' && (contains(github.event.pull_request.labels.*.name, 'ok-to-test') || contains(github.event.pull_request.labels.*.name, 'approved') || contains(github.event.pull_request.labels.*.name, 'lgtm')))) && @@ -38,7 +39,7 @@ jobs: - name: Create KIND cluster run: | - kind create cluster --name $KIND_CLUSTER --wait 5m + kind create cluster --name $KIND_CLUSTER --wait 10m - name: Set up kubernetes context run: | @@ -56,3 +57,9 @@ jobs: run: | # Delete the KIND cluster after tests kind delete cluster --name kind-$KIND_CLUSTER + + - name: Debug KIND Cluster when there is a failure + if: failure() + run: | + kubectl get pods --all-namespaces + kubectl describe nodes From 4db23f8c7bd861406454efac04d2de4ae3b0885d Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:12:36 -0700 Subject: [PATCH 06/12] increased the go test timeout to 30m to fix the github operator e2e test action. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- infra/feast-operator/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/feast-operator/Makefile b/infra/feast-operator/Makefile index 310d64afaaa..6984ac66e7f 100644 --- a/infra/feast-operator/Makefile +++ b/infra/feast-operator/Makefile @@ -117,7 +117,7 @@ test: build-installer fmt vet lint envtest ## Run tests. # Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors. .PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up. test-e2e: - go test ./test/e2e/ -v -ginkgo.v + go test -timeout 30m ./test/e2e/ -v -ginkgo.v .PHONY: lint lint: golangci-lint ## Run golangci-lint linter & yamllint From 1e551d35f8cf722873f67a55c2365d88d6ac375e Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:12:36 -0700 Subject: [PATCH 07/12] increased the go test timeout to 30m to fix the github operator e2e test action. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- .github/workflows/operator-e2e-integration-tests.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/operator-e2e-integration-tests.yml b/.github/workflows/operator-e2e-integration-tests.yml index 1eeb3733976..cbb505c3fe8 100644 --- a/.github/workflows/operator-e2e-integration-tests.yml +++ b/.github/workflows/operator-e2e-integration-tests.yml @@ -52,14 +52,16 @@ jobs: cd infra/feast-operator/ make test-e2e + - name: Debug KIND Cluster when there is a failure + if: failure() + run: | + kubectl get pods --all-namespaces + kubectl describe nodes + - name: Clean up if: always() run: | # Delete the KIND cluster after tests kind delete cluster --name kind-$KIND_CLUSTER - - name: Debug KIND Cluster when there is a failure - if: failure() - run: | - kubectl get pods --all-namespaces - kubectl describe nodes + From 0070ac8ed095cbcc5d0d19f870398908c338b434 Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:12:36 -0700 Subject: [PATCH 08/12] increased the go test timeout to 30m to fix the github operator e2e test action. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- infra/feast-operator/test/e2e/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/feast-operator/test/e2e/e2e_test.go b/infra/feast-operator/test/e2e/e2e_test.go index 9f88b5e7ce8..23637ff224b 100644 --- a/infra/feast-operator/test/e2e/e2e_test.go +++ b/infra/feast-operator/test/e2e/e2e_test.go @@ -135,7 +135,7 @@ var _ = Describe("controller", Ordered, func() { remoteFeatureStoreName := "simple-feast-remote-setup" - validateTheFeatureStoreCustomResource(remoteRegistryNs, remoteFeatureStoreName, 5*time.Minute) + validateTheFeatureStoreCustomResource(remoteRegistryNs, remoteFeatureStoreName, timeout) By("deleting the feast remote registry deployment") cmd = exec.Command("kubectl", "delete", "-f", From 60c10b1783f9d5e0c18dbe4d3197b5a64afe7bff Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:06:05 -0700 Subject: [PATCH 09/12] incorporating the code review comments. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- .../v1alpha1_remote_registry_featurestore.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml b/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml index 2d47e6c44eb..72b887f7589 100644 --- a/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml +++ b/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml @@ -11,5 +11,6 @@ spec: image: 'localhost/feastdev/feature-server:dev' registry: remote: - hostname: 'feast-simple-feast-setup-registry.default.svc.cluster.local:80' - + feastRef: + name: simple-feast-setup + namespace: remote-registry \ No newline at end of file From 41acec626c69b2a75116cd70b3b4c4fa36cf55f5 Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:06:05 -0700 Subject: [PATCH 10/12] incorporating the code review comments by using the feastRef. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- infra/feast-operator/test/e2e/test_util.go | 6 +++++- .../v1alpha1_remote_registry_featurestore.yaml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/infra/feast-operator/test/e2e/test_util.go b/infra/feast-operator/test/e2e/test_util.go index 2417084c141..9a6c37a9a0f 100644 --- a/infra/feast-operator/test/e2e/test_util.go +++ b/infra/feast-operator/test/e2e/test_util.go @@ -220,9 +220,13 @@ func isFeatureStoreHavingRemoteRegistry(namespace, featureStoreName string) (boo return false, nil // Return false if "remote" is not present } + // either remote hostname or feastRef should be available for remote config. hostname, ok := remote["hostname"].(string) if !ok || hostname == "" { - return false, nil // Return false if "hostname" is missing or empty + _, feastRefOk := remote["feastRef"].(map[string]interface{}) + if !feastRefOk { + return false, nil + } } return true, nil // Return true if "remote.hostname" exists and has a value diff --git a/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml b/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml index 72b887f7589..61c010f0576 100644 --- a/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml +++ b/infra/feast-operator/test/testdata/feast_integration_test_crs/v1alpha1_remote_registry_featurestore.yaml @@ -13,4 +13,4 @@ spec: remote: feastRef: name: simple-feast-setup - namespace: remote-registry \ No newline at end of file + namespace: default \ No newline at end of file From 7db4bf534f9c861226a60640bf07b730ad1f31c9 Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:02:36 -0700 Subject: [PATCH 11/12] incorporating the code review comments by marshaling json to the go struct object rather than map. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- infra/feast-operator/test/e2e/test_util.go | 26 ++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/infra/feast-operator/test/e2e/test_util.go b/infra/feast-operator/test/e2e/test_util.go index 9a6c37a9a0f..ed7cbabe957 100644 --- a/infra/feast-operator/test/e2e/test_util.go +++ b/infra/feast-operator/test/e2e/test_util.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/feast-dev/feast/infra/feast-operator/api/v1alpha1" "os/exec" "strings" "time" @@ -209,25 +210,22 @@ func isFeatureStoreHavingRemoteRegistry(namespace, featureStoreName string) (boo } // Parse the JSON into a map - var registryData map[string]interface{} - if err := json.Unmarshal([]byte(result), ®istryData); err != nil { + var registryConfig v1alpha1.Registry + if err := json.Unmarshal([]byte(result), ®istryConfig); err != nil { return false, err // Return false on JSON parsing failure } - // Navigate the map to check for the "remote.hostname" field - remote, ok := registryData["remote"].(map[string]interface{}) - if !ok { - return false, nil // Return false if "remote" is not present + if registryConfig.Remote == nil { + return false, nil } - // either remote hostname or feastRef should be available for remote config. - hostname, ok := remote["hostname"].(string) - if !ok || hostname == "" { - _, feastRefOk := remote["feastRef"].(map[string]interface{}) - if !feastRefOk { - return false, nil - } + hasHostname := registryConfig.Remote.Hostname != nil + hasValidFeastRef := registryConfig.Remote.FeastRef != nil && + registryConfig.Remote.FeastRef.Name != "" + + if hasHostname || hasValidFeastRef { + return true, nil } - return true, nil // Return true if "remote.hostname" exists and has a value + return false, nil } From 2d849653dda3ce2720c39e7e69cb2bf663a65d74 Mon Sep 17 00:00:00 2001 From: lrangine <19699092+lokeshrangineni@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:17:19 -0700 Subject: [PATCH 12/12] Fixing the lint error. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com> --- infra/feast-operator/test/e2e/test_util.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infra/feast-operator/test/e2e/test_util.go b/infra/feast-operator/test/e2e/test_util.go index ed7cbabe957..7d44ac1296a 100644 --- a/infra/feast-operator/test/e2e/test_util.go +++ b/infra/feast-operator/test/e2e/test_util.go @@ -5,10 +5,11 @@ import ( "encoding/json" "errors" "fmt" - "github.com/feast-dev/feast/infra/feast-operator/api/v1alpha1" "os/exec" "strings" "time" + + "github.com/feast-dev/feast/infra/feast-operator/api/v1alpha1" ) // dynamically checks if all conditions of custom resource featurestore are in "Ready" state.