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

Add Communication Matrix Module #1716

Closed
Closed
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
17 changes: 9 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ require (
github.com/blang/semver/v4 v4.0.0
github.com/davecgh/go-spew v1.1.1
github.com/distribution/distribution/v3 v3.0.0-20230511163743-f7717b7855ca
github.com/evanphx/json-patch v4.12.0+incompatible
github.com/evanphx/json-patch v5.6.0+incompatible
github.com/fvbommel/sortorder v1.1.0
github.com/go-ldap/ldap/v3 v3.4.3
github.com/gonum/graph v0.0.0-20170401004347-50b27dea7ebb
github.com/google/gnostic-models v0.6.8
github.com/google/go-cmp v0.6.0
github.com/imdario/mergo v0.3.7
github.com/imdario/mergo v0.3.13
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/runc v1.1.10
Expand All @@ -25,9 +25,9 @@ require (
github.com/pkg/profile v1.3.0
github.com/prometheus/client_golang v1.16.0
github.com/robfig/cron v1.2.0
github.com/sirupsen/logrus v1.9.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace
github.com/stretchr/testify v1.8.4
go.etcd.io/etcd/client/v3 v3.5.10
golang.org/x/crypto v0.14.0
Expand All @@ -43,7 +43,8 @@ require (
k8s.io/component-base v0.29.0
k8s.io/klog/v2 v2.110.1
k8s.io/kube-aggregator v0.29.0
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
k8s.io/utils v0.0.0-20231127182322-b307cd553661
sigs.k8s.io/controller-runtime v0.16.2
sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96
sigs.k8s.io/yaml v1.3.0
)
Expand All @@ -61,6 +62,7 @@ require (
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
Expand Down Expand Up @@ -108,10 +110,9 @@ require (
go.opentelemetry.io/otel/sdk v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.19.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.19.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
go.uber.org/zap v1.25.0 // indirect
golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/term v0.13.0 // indirect
Expand Down
56 changes: 26 additions & 30 deletions go.sum

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions pkg/network/commatrix/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FORMAT ?= csv
CLUSTER_ENV ?= baremetal
DEST_DIR ?= .

GO_SRC := cmd/main.go

EXECUTABLE := commatrix

.DEFAULT_GOAL := run

build:
go build -o $(EXECUTABLE) $(GO_SRC)

generate: build
mkdir -p $(DEST_DIR)/communication-matrix
./$(EXECUTABLE) -format=$(FORMAT) -env=$(CLUSTER_ENV) -destDir=$(DEST_DIR)/communication-matrix

clean:
@rm -f $(EXECUTABLE)
35 changes: 35 additions & 0 deletions pkg/network/commatrix/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package client

import (
appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
discoveryv1client "k8s.io/client-go/kubernetes/typed/discovery/v1"
"k8s.io/client-go/tools/clientcmd"
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
)

type ClientSet struct {
corev1client.CoreV1Interface
appsv1client.AppsV1Interface
discoveryv1client.DiscoveryV1Interface
runtimeclient.Client
}

func New(kubeconfigPath string) (*ClientSet, error) {
config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
if err != nil {
return nil, err
}

clientSet := &ClientSet{}
clientSet.CoreV1Interface = corev1client.NewForConfigOrDie(config)
clientSet.AppsV1Interface = appsv1client.NewForConfigOrDie(config)
clientSet.DiscoveryV1Interface = discoveryv1client.NewForConfigOrDie(config)

clientSet.Client, err = runtimeclient.New(config, runtimeclient.Options{})
if err != nil {
return nil, err
}

return clientSet, nil
}
160 changes: 160 additions & 0 deletions pkg/network/commatrix/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package main

import (
"context"
"flag"
"fmt"
"os"
"path"
"path/filepath"

"github.com/openshift/library-go/pkg/network/commatrix"
clientutil "github.com/openshift/library-go/pkg/network/commatrix/client"
"github.com/openshift/library-go/pkg/network/commatrix/ss"
"github.com/openshift/library-go/pkg/network/commatrix/types"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func main() {
var (
destDir string
format string
envStr string
customEntriesPath string
printFn func(m *types.ComMatrix) ([]byte, error)
)

flag.StringVar(&destDir, "destDir", "communication-matrix", "Output files dir")
flag.StringVar(&format, "format", "csv", "Desired format (json,yaml,csv)")
flag.StringVar(&envStr, "env", "baremetal", "Cluster environment (baremetal/aws)")
flag.StringVar(&customEntriesPath, "customEntriesPath", "", "Add custom entries from a JSON file to the matrix")

flag.Parse()

switch format {
case "json":
printFn = types.ToJSON
case "csv":
printFn = types.ToCSV
case "yaml":
printFn = types.ToYAML
default:
panic(fmt.Sprintf("invalid format: %s. Please specify json, csv, or yaml.", format))
}

kubeconfig, ok := os.LookupEnv("KUBECONFIG")
if !ok {
panic("must set the KUBECONFIG environment variable")
}

var env commatrix.Env
switch envStr {
case "baremetal":
env = commatrix.Baremetal
case "aws":
env = commatrix.AWS
default:
panic(fmt.Sprintf("invalid cluster environment: %s", envStr))
}

// TODO: customEntries file
mat, err := commatrix.New(kubeconfig, customEntriesPath, env)
if err != nil {
panic(fmt.Sprintf("failed to create the communication matrix: %s", err))
}

res, err := printFn(mat)
if err != nil {
panic(err)
}

comMatrixFileName := filepath.Join(destDir, fmt.Sprintf("communication-matrix.%s", format))
err = os.WriteFile(comMatrixFileName, []byte(string(res)), 0644)
if err != nil {
panic(err)
}

cs, err := clientutil.New(kubeconfig)
if err != nil {
panic(err)
}

tcpFile, err := os.OpenFile(path.Join(destDir, "raw-ss-tcp"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
defer tcpFile.Close()

udpFile, err := os.OpenFile(path.Join(destDir, "raw-ss-udp"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
defer udpFile.Close()

nodesList, err := cs.Nodes().List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err)
}

nodesComDetails := []types.ComDetails{}
for _, n := range nodesList.Items {
// TODO: can be improved with go routines
cds, err := ss.CreateComDetailsFromNode(cs, &n, tcpFile, udpFile)
if err != nil {
panic(err)
}

nodesComDetails = append(nodesComDetails, cds...)
}
cleanedComDetails := types.RemoveDups(nodesComDetails)
ssComMat := types.ComMatrix{Matrix: cleanedComDetails}

res, err = printFn(&ssComMat)
if err != nil {
panic(err)
}

ssMatrixFileName := filepath.Join(destDir, fmt.Sprintf("ss-generated-matrix.%s", format))
err = os.WriteFile(ssMatrixFileName, []byte(string(res)), 0644)
if err != nil {
panic(err)
}

diff := ""
for _, cd1 := range mat.Matrix {
found := false
for _, cd2 := range ssComMat.Matrix {
if cd1.Equals(cd2) {
found = true
break
}
}
if !found {
diff += fmt.Sprintf("+ %s\n", cd1)
continue
}
diff += fmt.Sprintf("%s\n", cd1)
}

for _, cd1 := range ssComMat.Matrix {
found := false
for _, cd2 := range mat.Matrix {
if cd1.Equals(cd2) {
found = true
break
}
}
if !found {
diff += fmt.Sprintf("- %s\n", cd1)
continue
}
diff += fmt.Sprintf("%s\n", cd1)
}

err = os.WriteFile(filepath.Join(destDir, "matrix-diff-ss"),
[]byte(diff),
0644)
if err != nil {
panic(err)
}
}
114 changes: 114 additions & 0 deletions pkg/network/commatrix/commatrix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package commatrix

import (
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"

"github.com/openshift/library-go/pkg/network/commatrix/client"
"github.com/openshift/library-go/pkg/network/commatrix/endpointslices"
"github.com/openshift/library-go/pkg/network/commatrix/types"
)

type Env int

const (
Baremetal Env = iota
AWS
)

// New initializes a ComMatrix using Kubernetes cluster data.
// It takes kubeconfigPath for cluster access to fetch EndpointSlice objects,
// detailing open ports for ingress traffic.
// customEntriesPath allows adding custom entries from a JSON file to the matrix.
// Returns a pointer to ComMatrix and error. Entries include traffic direction, protocol,
// port number, namespace, service name, pod, container, node role, and flow optionality for OpenShift.
func New(kubeconfigPath string, customEntriesPath string, e Env) (*types.ComMatrix, error) {
res := make([]types.ComDetails, 0)

cs, err := client.New(kubeconfigPath)
if err != nil {
return nil, fmt.Errorf("failed creating the k8s client: %w", err)
}

epSlicesInfo, err := endpointslices.GetIngressEndpointSlicesInfo(cs)
if err != nil {
return nil, fmt.Errorf("failed getting endpointslices: %w", err)
}

epSliceComDetails, err := endpointslices.ToComDetails(cs, epSlicesInfo)
if err != nil {
return nil, err
}
res = append(res, epSliceComDetails...)

staticEntries, err := getStaticEntries(e)
if err != nil {
return nil, err
}

res = append(res, staticEntries...)

if customEntriesPath != "" {
customComDetails, err := addFromFile(customEntriesPath)
if err != nil {
return nil, fmt.Errorf("failed fetching custom entries from file %s err: %w", customEntriesPath, err)
}

res = append(res, customComDetails...)
}

return &types.ComMatrix{Matrix: res}, nil
}

func addFromFile(fp string) ([]types.ComDetails, error) {
var res []types.ComDetails
f, err := os.Open(filepath.Clean(fp))
if err != nil {
return nil, fmt.Errorf("failed to open file %s: %v", fp, err)
}
defer f.Close()
raw, err := io.ReadAll(f)
if err != nil {
return nil, fmt.Errorf("failed to read file %s: %v", fp, err)
}

err = json.Unmarshal(raw, &res)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal custom entries file: %v", err)
}

return res, nil
}

func getStaticEntries(e Env) ([]types.ComDetails, error) {
var (
envComDetails []types.ComDetails
genericComDetails []types.ComDetails
)
switch e {
case Baremetal:
err := json.Unmarshal([]byte(baremetalStaticEntries), &envComDetails)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal static entries: %v", err)
}
case AWS:
err := json.Unmarshal([]byte(awsCloudStaticEntries), &envComDetails)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal static entries: %v", err)
}
default:
return nil, fmt.Errorf("invalid value for cluster environment")
}

err := json.Unmarshal([]byte(generalStaticEntries), &genericComDetails)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal static entries: %v", err)
}

res := append(envComDetails, genericComDetails...)

return res, nil
}
Loading