Skip to content

Commit

Permalink
Better error handling & fix tests
Browse files Browse the repository at this point in the history
- Modified the way data is unmarshled
- Moved specific errors to different function
- Avoid nil values
- Fix TestEventObject & TestStructResourceLog tests.
  • Loading branch information
ralongit committed Oct 2, 2023
1 parent 0242748 commit 6cdf90f
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 62 deletions.
45 changes: 24 additions & 21 deletions resources/clusterResources.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,30 +216,33 @@ func GetClusterRoleBinding(clusterRoleBindingName string) (relatedClusterRoleBin

// GetClusterRelatedResources retrieves all related resources for a given resource kind, name and namespace.
func GetClusterRelatedResources(resourceKind string, resourceName string, namespace string) (relatedClusterServices common.RelatedClusterServices) {
//
log.Printf("[DEBUG] Attemping to parse Resource: %s of kind: %s related cluster services.\n", resourceName, resourceKind)

common.CreateClusterClient()

switch resourceKind {
case "ConfigMap":
relatedClusterServices = ConfigMapRelatedWorkloads(resourceName)
case "Secret":
relatedClusterServices = SecretRelatedWorkloads(resourceName)
case "ClusterRoleBinding":
relatedClusterServices = ClusterRoleBindingRelatedWorkloads(resourceName)
case "ServiceAccount":
relatedClusterServices = ServiceAccountRelatedWorkloads(resourceName)
case "ClusterRole":
relatedClusterServices = ClusterRoleRelatedWorkloads(resourceName)
case "Deployment":
relatedClusterServices = DeploymentRelatedResources(resourceName, namespace)
case "DaemonSet":
relatedClusterServices = DaemonSetRelatedResources(resourceName, namespace)
case "StatefulSet":
relatedClusterServices = StatefulSetRelatedResources(resourceName, namespace)
default:
log.Printf("[ERROR] Unknown resource kind %s", resourceKind)
if common.K8sClient != nil {
switch resourceKind {
case "ConfigMap":
relatedClusterServices = ConfigMapRelatedWorkloads(resourceName)
case "Secret":
relatedClusterServices = SecretRelatedWorkloads(resourceName)
case "ClusterRoleBinding":
relatedClusterServices = ClusterRoleBindingRelatedWorkloads(resourceName)
case "ServiceAccount":
relatedClusterServices = ServiceAccountRelatedWorkloads(resourceName)
case "ClusterRole":
relatedClusterServices = ClusterRoleRelatedWorkloads(resourceName)
case "Deployment":
relatedClusterServices = DeploymentRelatedResources(resourceName, namespace)
case "DaemonSet":
relatedClusterServices = DaemonSetRelatedResources(resourceName, namespace)
case "StatefulSet":
relatedClusterServices = StatefulSetRelatedResources(resourceName, namespace)
default:
log.Printf("[ERROR] Unknown resource kind %s", resourceKind)
}

} else {
log.Printf("Failed to parse Resource: %s of kind: %s related cluster services, couldn't create a K8S client.\n", resourceName, resourceKind)
}

return relatedClusterServices
Expand Down
36 changes: 18 additions & 18 deletions resources/resourceInformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"main.go/common"
"os"
"os/signal"
"reflect"
"sync"
)

Expand Down Expand Up @@ -195,29 +196,19 @@ func EventObject(rawObj map[string]interface{}, isNew bool) (resourceObject comm
return resourceObject
}

// Check if the newObject field of rawObj is nil, if it is required
if isNew && rawObj["newObject"] == nil {
log.Println("[ERROR] rawObj does not have required field: newObject.")
// Return an empty KubernetesEvent object if the raw object is invalid
return resourceObject
}

// Check if the oldObject field of rawObj is nil, if it is required
if !isNew && rawObj["oldObject"] == nil {
log.Println("[ERROR] rawObj does not have required field: oldObject.")
// Return an empty KubernetesEvent object if the raw object is invalid
return resourceObject
}

// Initialize an empty unstructured object
rawUnstructuredObj := unstructured.Unstructured{}
// Initialize a buffer to store the JSON-encoded raw object
var buffer bytes.Buffer
// Encode the raw object into JSON and write it to the buffer
json.NewEncoder(&buffer).Encode(rawObj)
err := json.NewEncoder(&buffer).Encode(rawObj)
if err != nil {
log.Printf("Failed to encode unstructed resource object bytes:\n%v\nError:\n%v", rawObj, err)

}

// Unmarshal the JSON-encoded raw object into a KubernetesEvent object
err := json.Unmarshal(buffer.Bytes(), &resourceObject)
err = json.Unmarshal(buffer.Bytes(), &resourceObject)
if err != nil {
log.Printf("Failed to unmarshal resource object:\n%v\nError:\n%v", rawObj, err)
} else {
Expand All @@ -236,12 +227,17 @@ func EventObject(rawObj map[string]interface{}, isNew bool) (resourceObject comm

// StructResourceLog receives an event and logs it in a structured format.
func StructResourceLog(event map[string]interface{}) (isStructured bool, marshaledEvent []byte) {

// Check if event is nil
if event == nil {
log.Println("[ERROR] Event is nil")
return false, nil
}
// Check if the newObject field of rawObj is nil, if it is required
if event["newObject"] == nil {
log.Println("[ERROR] rawObj does not have required field: newObject.")
// Return an empty KubernetesEvent object if the raw object is invalid
return
}

// Assert that event["eventType"] is a string
eventType, ok := event["eventType"].(string)
Expand Down Expand Up @@ -286,7 +282,10 @@ func StructResourceLog(event map[string]interface{}) (isStructured bool, marshal
}

// Get the related cluster services for the resource
event["relatedClusterServices"] = GetClusterRelatedResources(resourceKind, resourceName, resourceNamespace)
relatedClusterServices := GetClusterRelatedResources(resourceKind, resourceName, resourceNamespace)
if !reflect.ValueOf(relatedClusterServices).IsZero() {
event["relatedClusterServices"] = relatedClusterServices
}
event["message"] = msg

// Marshal the event to a string
Expand All @@ -296,6 +295,7 @@ func StructResourceLog(event map[string]interface{}) (isStructured bool, marshal
}

// Mark the goroutine as done
wg.Add(1)
defer wg.Done()

// Return true indicating the log is structured
Expand Down
52 changes: 29 additions & 23 deletions resources/resourceInformer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package resources

import (
"encoding/json"
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand All @@ -11,7 +10,6 @@ import (
"k8s.io/client-go/tools/cache"
"log"
"main.go/common"
"sigs.k8s.io/yaml"
"testing"
)

Expand Down Expand Up @@ -41,23 +39,26 @@ func TestCreateResourceInformer(t *testing.T) {
// TestEventObject tests the creation of an event object from a map
func TestEventObject(t *testing.T) {
testDeployment := GetTestDeployment()
// Marshal the struct to JSON
jsonData, err := yaml.Marshal(testDeployment)
jsonData, err := json.Marshal(testDeployment)
if err != nil {
fmt.Printf("error: %s", err)
return
t.Fatalf("Failed to marshal test deployment: %s", err)
}

// Unmarshal the JSON to a map
var deploymentMap map[string]interface{}
err = yaml.Unmarshal(jsonData, &deploymentMap)
if err != nil {
fmt.Printf("error: %s", err)
return
if err = json.Unmarshal(jsonData, &deploymentMap); err != nil {
t.Fatalf("Failed to unmarshal deployment map: %s", err)
}

// Deep copy of the map
mapBytes, _ := json.Marshal(deploymentMap)
var newObject map[string]interface{}
if err = json.Unmarshal(mapBytes, &newObject); err != nil {
t.Fatalf("Failed to unmarshal new object: %s", err)
}

deploymentMap["eventType"] = common.EventTypeAdded
deploymentMap["kind"] = "Deployment"
deploymentMap["newObject"] = &deploymentMap
deploymentMap["newObject"] = newObject
eventObject := EventObject(deploymentMap, true)

if eventObject.Kind != "Deployment" {
Expand All @@ -75,24 +76,29 @@ func TestEventObject(t *testing.T) {

// TestStructResourceLog tests the creation of a structured resource log
func TestStructResourceLog(t *testing.T) {
var deploymentMap map[string]interface{}
testDeployment := GetTestDeployment()
jsonDeployment, err := json.Marshal(testDeployment)
jsonData, err := json.Marshal(testDeployment)
if err != nil {
t.Errorf("Failed to marshal test deployment.\nError:\n %v", err)
t.Fatalf("Failed to marshal test deployment: %s", err)
}

err = json.Unmarshal(jsonDeployment, &deploymentMap)
if err != nil {
t.Errorf("Failed to unmarshal test deployment.\nError:\n %v", err)
var deploymentMap map[string]interface{}
if err = json.Unmarshal(jsonData, &deploymentMap); err != nil {
t.Fatalf("Failed to unmarshal deployment map: %s", err)
}
deploymentEventMap := map[string]interface{}{

"eventType": common.EventTypeAdded,
"kind": "Deployment",
"newObject": deploymentMap,
// Deep copy of the map
mapBytes, _ := json.Marshal(deploymentMap)
var newObject map[string]interface{}
if err = json.Unmarshal(mapBytes, &newObject); err != nil {
t.Fatalf("Failed to unmarshal new object: %s", err)
}
isStructured, _ := StructResourceLog(deploymentEventMap)

deploymentMap["eventType"] = common.EventTypeAdded
deploymentMap["kind"] = "Deployment"
deploymentMap["newObject"] = newObject

isStructured, _ := StructResourceLog(deploymentMap)

if !isStructured {
t.Errorf("Failed to structure resource log")
Expand Down

0 comments on commit 6cdf90f

Please sign in to comment.