Skip to content

Commit

Permalink
feat: Add code for exporter (httpexporter, nimbuspolicy watcher)
Browse files Browse the repository at this point in the history
  • Loading branch information
b0m313 committed Jan 2, 2024
1 parent bcce001 commit 396ad8b
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 0 deletions.
63 changes: 63 additions & 0 deletions nimbus-operator/exporter/httpexporter/http_nimbus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Authors of Nimbus

// Initialize HTTP Client: Set up the client for HTTP communication.
// Format Nimbus Policy Data: Convert Nimbus Policy data into JSON format.
// Send Data: Send the converted data to the adapter's URL using a POST request.
// Process Response: Handle the response from the adapter and log as necessary.

package httpexporter

import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"

v1 "github.com/5GSEC/nimbus/nimbus-operator/api/v1"
)

// HttpNimbusExporter struct defines the HTTP client and the URL for exporting Nimbus policies.
type HttpNimbusExporter struct {
client *http.Client
url string
}

// NewHttpNimbusExporter creates a new HttpNimbusExporter with the provided URL.
func NewHttpNimbusExporter(url string) *HttpNimbusExporter {
return &HttpNimbusExporter{
client: &http.Client{},
url: url,
}
}

// ExportNimbusPolicy exports a NimbusPolicy to a remote server via HTTP POST.
func (h *HttpNimbusExporter) ExportNimbusPolicy(ctx context.Context, policy *v1.NimbusPolicy) error {
// Convert the NimbusPolicy into JSON format.
data, err := json.Marshal(policy)
if err != nil {
return fmt.Errorf("failed to marshal NimbusPolicy: %v", err)
}

// Create a new HTTP POST request with the policy data.
req, err := http.NewRequestWithContext(ctx, "POST", h.url, bytes.NewBuffer(data))
if err != nil {
return fmt.Errorf("failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")

// Send the request to the server.
resp, err := h.client.Do(req)
if err != nil {
return fmt.Errorf("failed to send request: %v", err)
}
defer resp.Body.Close()

// Check if the response status is OK (HTTP 200).
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("non-OK response received: %v", resp.Status)
}

return nil
}
101 changes: 101 additions & 0 deletions nimbus-operator/exporter/nimbuspolicy/nimbuspolicy_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Authors of Nimbus

package nimbuspolicy

import (
"context"
"fmt"

"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"

v1 "github.com/5GSEC/nimbus/nimbus-operator/api/v1"
"github.com/5GSEC/nimbus/nimbus-operator/exporter/httpexporter"
watcher "github.com/5GSEC/nimbus/nimbus-operator/receiver/watcher"
)

// NimbusPolicyReconciler reconciles a NimbusPolicy object.
type NimbusPolicyReconciler struct {
client.Client
Scheme *runtime.Scheme
WatcherNimbusPolicy *watcher.WatcherNimbusPolicy
}

// NewNimbusPolicyReconciler creates a new instance of NimbusPolicyReconciler.
// It initializes the WatcherNimbusPolicy which watches and reacts to changes in NimbusPolicy objects.
func NewNimbusPolicyReconciler(client client.Client, scheme *runtime.Scheme) *NimbusPolicyReconciler {
if client == nil {
fmt.Println("NimbusPolicyReconciler: Client is nil")
return nil
}

watcherNimbusPolicy, err := watcher.NewWatcherNimbusPolicy(client)
if err != nil {
fmt.Println("NimbusPolicyReconciler: Failed to initialize WatcherNimbusPolicy:", err)
return nil
}

return &NimbusPolicyReconciler{
Client: client,
Scheme: scheme,
WatcherNimbusPolicy: watcherNimbusPolicy,
}
}

//+kubebuilder:rbac:groups=intent.security.nimbus.com,resources=nimbuspolicies,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=intent.security.nimbus.com,resources=nimbuspolicies/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=intent.security.nimbus.com,resources=nimbuspolicies/finalizers,verbs=update

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the NimbusPolicy object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
func (r *NimbusPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := log.FromContext(ctx)

if r.WatcherNimbusPolicy == nil {
fmt.Println("NimbusPolicyReconciler: WatcherNimbusPolicy is nil")
return ctrl.Result{}, fmt.Errorf("WatcherNimbusPolicy is not properly initialized")
}

nimPol, err := r.WatcherNimbusPolicy.Reconcile(ctx, req)
if err != nil {
log.Error(err, "Error in WatcherNimbusPolicy.Reconcile", "Request", req.NamespacedName)
return ctrl.Result{}, err
}

if nimPol != nil {
log.Info("NimbusPolicy resource found", "Name", req.Name, "Namespace", req.Namespace)
} else {
log.Info("NimbusPolicy resource not found", "Name", req.Name, "Namespace", req.Namespace)
}

// Exporting the NimbusPolicy if it is found.
if nimPol != nil {
exporter := httpexporter.NewHttpNimbusExporter("http://localhost:13000/api/v1/nimbus/export") // Update the URL as needed.
err := exporter.ExportNimbusPolicy(ctx, nimPol)
if err != nil {
log.Error(err, "Failed to export NimbusPolicy")
return ctrl.Result{}, err
}
log.Info("NimbusPolicy exported successfully")
}

return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
// It registers the NimbusPolicyReconciler to manage NimbusPolicy resources.
func (r *NimbusPolicyReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&v1.NimbusPolicy{}).
Complete(r)
}
77 changes: 77 additions & 0 deletions nimbus-operator/exporter/nimbuspolicy/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Authors of Nimbus

package nimbuspolicy

import (
"fmt"
"path/filepath"
"runtime"
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"

intentv1 "github.com/5GSEC/nimbus/api/v1"
//+kubebuilder:scaffold:imports
)

// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.

var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment

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

RunSpecs(t, "Controller Suite")
}

var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))

By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: true,

// The BinaryAssetsDirectory is only required if you want to run the tests directly
// without call the makefile target test. If not informed it will look for the
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
// Note that you must have the required binaries setup under the bin directory to perform
// the tests directly. When we run make test it will be setup and used automatically.
BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
fmt.Sprintf("1.28.3-%s-%s", runtime.GOOS, runtime.GOARCH)),
}

var err error
// cfg is defined in this file globally.
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())

err = intentv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())

//+kubebuilder:scaffold:scheme

k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())

})

var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})

0 comments on commit 396ad8b

Please sign in to comment.