Skip to content

Commit 954de60

Browse files
Release v1.5.0
2 parents 5b83a7f + 7ae64c9 commit 954de60

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1006
-895
lines changed

.circleci/config.yml

+6-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- karto
1313
build-front:
1414
docker:
15-
- image: cimg/node:12.16.3
15+
- image: cimg/node:14.15.1
1616
working_directory: /home/circleci/karto
1717
steps:
1818
- attach_workspace:
@@ -44,7 +44,7 @@ jobs:
4444
- karto/front/build
4545
build-back:
4646
docker:
47-
- image: cimg/go:1.14.2
47+
- image: cimg/go:1.15.6
4848
working_directory: /home/circleci/karto
4949
steps:
5050
- attach_workspace:
@@ -94,16 +94,16 @@ jobs:
9494
command: |
9595
docker build -t zenikalabs/karto .
9696
docker tag zenikalabs/karto zenikalabs/karto:v1
97-
docker tag zenikalabs/karto zenikalabs/karto:v1.4
98-
docker tag zenikalabs/karto zenikalabs/karto:v1.4.0
97+
docker tag zenikalabs/karto zenikalabs/karto:v1.5
98+
docker tag zenikalabs/karto zenikalabs/karto:v1.5.0
9999
- run:
100100
name: Push docker image
101101
command: |
102102
echo "$DOCKER_PASS" | docker login --username $DOCKER_USER --password-stdin
103103
docker push zenikalabs/karto
104104
docker push zenikalabs/karto:v1
105-
docker push zenikalabs/karto:v1.4
106-
docker push zenikalabs/karto:v1.4.0
105+
docker push zenikalabs/karto:v1.5
106+
docker push zenikalabs/karto:v1.5.0
107107
workflows:
108108
version: 2
109109
build-test-and-deploy:

README.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,19 @@ The left part of the screen contains the controls for the main view:
2424
- Include ingress neighbors: display pods that can reach those in the current selection
2525
- Include egress neighbors: display pods that can be reached by those in the current selection
2626
- Auto refresh: refresh the view every 5 seconds
27+
- Auto zoom: zoom automatically to fit all elements in the screen
2728
- Show namespace prefix: include the namespace in pod names
2829
- Highlight non isolated pods (ingress/egress): color pods with no ingress/egress network policy
2930
- Always display large datasets: always try to display large sets of pods and routes (may slow down your browser)
3031

3132
The main view shows the graph of pods and allowed routes in your selection:
3233
- Zoom in and out by scrolling
3334
- Drag and drop graph elements to draw the perfect map of your cluster
35+
- Hover over any graph element to display details: name, namespace, labels, isolation (ingress/egress)... and more!
3436

35-
Hover over any graph element to display details: name, namespace, labels, isolation (ingress/egress)... and more!
37+
In the top left part of the screen you will find action buttons to:
38+
- Export the current graph as PNG to use it in slides or share it
39+
- Go fullscreen and use Karto as an office (or situation room!) dashboard
3640

3741
## Installation
3842

@@ -89,8 +93,8 @@ Simply download the Karto binary from the [releases page](https://github.com/Zen
8993
### Prerequisites
9094

9195
The following tools must be available locally:
92-
- [Go](https://golang.org/doc/install) (tested with Go 1.14)
93-
- [NodeJS 10+](https://nodejs.org/en/download/) (tested with NodeJS 10)
96+
- [Go](https://golang.org/doc/install) (tested with Go 1.15)
97+
- [NodeJS](https://nodejs.org/en/download/) (tested with NodeJS 14)
9498

9599
### Run the frontend in dev mode
96100

File renamed without changes.

back/analyzer/pod/pod_analyzer_test.go back/analyzer/pod/analyzer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"testing"
99
)
1010

11-
func Test_Analyze(t *testing.T) {
11+
func TestAnalyze(t *testing.T) {
1212
type args struct {
1313
clusterState ClusterState
1414
}
File renamed without changes.

back/analyzer/analysis_scheduler_test.go back/analyzer/scheduler_test.go

+18-18
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package analyzer
22

33
import (
4-
"fmt"
54
"github.com/google/go-cmp/cmp"
65
appsv1 "k8s.io/api/apps/v1"
76
corev1 "k8s.io/api/core/v1"
@@ -14,9 +13,10 @@ import (
1413
"karto/types"
1514
"reflect"
1615
"testing"
16+
"time"
1717
)
1818

19-
func Test_Analyze(t *testing.T) {
19+
func TestAnalyze(t *testing.T) {
2020
type args struct {
2121
clusterState types.ClusterState
2222
}
@@ -86,7 +86,7 @@ func Test_Analyze(t *testing.T) {
8686
TargetReplicaSets: []types.ReplicaSetRef{replicaSetRef1}}
8787
deployment2 := &types.Deployment{Name: k8sDeployment2.Name, Namespace: k8sDeployment2.Namespace,
8888
TargetReplicaSets: []types.ReplicaSetRef{replicaSetRef2}}
89-
var tests = []struct {
89+
tests := []struct {
9090
name string
9191
mocks mocks
9292
args args
@@ -176,9 +176,13 @@ func Test_Analyze(t *testing.T) {
176176
resultsChannel := make(chan types.AnalysisResult)
177177
go analyzer.AnalyzeOnClusterStateChange(clusterStateChannel, resultsChannel)
178178
clusterStateChannel <- tt.args.clusterState
179-
analysisResult := <-resultsChannel
180-
if diff := cmp.Diff(tt.expectedAnalysisResult, analysisResult); diff != "" {
181-
t.Errorf("Analyze() result mismatch (-want +got):\n%s", diff)
179+
select {
180+
case analysisResult := <-resultsChannel:
181+
if diff := cmp.Diff(tt.expectedAnalysisResult, analysisResult); diff != "" {
182+
t.Errorf("Analyze() result mismatch (-want +got):\n%s", diff)
183+
}
184+
case <-time.After(3 * time.Second):
185+
t.Errorf("Test timed out (nothing was received on the channel)")
182186
}
183187
})
184188
}
@@ -200,10 +204,8 @@ func (mock mockPodAnalyzer) Analyze(clusterState pod.ClusterState) pod.AnalysisR
200204
return call.returnValue
201205
}
202206
}
203-
fmt.Printf("mockPodAnalyzer was called with unexpected arguments: \n")
204-
fmt.Printf("\tclusterState=%s\n", clusterState)
205-
mock.t.FailNow()
206-
panic("unreachable but required to compile")
207+
mock.t.Fatalf("mockPodAnalyzer was called with unexpected arguments: \n\tclusterState: %s\n", clusterState)
208+
return pod.AnalysisResult{}
207209
}
208210

209211
func createMockPodAnalyzer(t *testing.T, calls []mockPodAnalyzerCall) pod.Analyzer {
@@ -229,10 +231,9 @@ func (mock mockTrafficAnalyzer) Analyze(clusterState traffic.ClusterState) traff
229231
return call.returnValue
230232
}
231233
}
232-
fmt.Printf("mockTrafficAnalyzer was called with unexpected arguments: \n")
233-
fmt.Printf("\tclusterState:%s\n", clusterState)
234-
mock.t.FailNow()
235-
panic("unreachable but required to compile")
234+
mock.t.Fatalf("mockTrafficAnalyzer was called with unexpected arguments: \n\tclusterState: %s\n",
235+
clusterState)
236+
return traffic.AnalysisResult{}
236237
}
237238

238239
func createMockTrafficAnalyzer(t *testing.T, calls []mockTrafficAnalyzerCall) traffic.Analyzer {
@@ -258,10 +259,9 @@ func (mock mockWorkloadAnalyzer) Analyze(clusterState workload.ClusterState) wor
258259
return call.returnValue
259260
}
260261
}
261-
fmt.Printf("mockWorkloadAnalyzer was called with unexpected arguments: \n")
262-
fmt.Printf("\tclusterState:%s\n", clusterState)
263-
mock.t.FailNow()
264-
panic("unreachable but required to compile")
262+
mock.t.Fatalf("mockWorkloadAnalyzer was called with unexpected arguments: \n\tclusterState: %s\n",
263+
clusterState)
264+
return workload.AnalysisResult{}
265265
}
266266

267267
func createMockWorkloadAnalyzer(t *testing.T, calls []mockWorkloadAnalyzerCall) workload.Analyzer {

back/analyzer/traffic/allowedroute/allowed_route_analyzer.go back/analyzer/traffic/allowedroute/analyzer.go

+12-13
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,18 @@ import (
1010
"sort"
1111
)
1212

13+
const portWildcard = -1
14+
1315
type Analyzer interface {
1416
Analyze(sourcePodIsolation *shared.PodIsolation, targetPodIsolation *shared.PodIsolation,
1517
namespaces []*corev1.Namespace) *types.AllowedRoute
1618
}
1719

1820
type analyzerImpl struct {
19-
portWildcard int32
2021
}
2122

2223
func NewAnalyzer() Analyzer {
23-
return analyzerImpl{
24-
portWildcard: -1,
25-
}
24+
return analyzerImpl{}
2625
}
2726

2827
func (analyzer analyzerImpl) Analyze(sourcePodIsolation *shared.PodIsolation, targetPodIsolation *shared.PodIsolation,
@@ -47,18 +46,18 @@ func (analyzer analyzerImpl) ingressPoliciesByPort(sourcePod *corev1.Pod, target
4746
namespaces []*corev1.Namespace) map[int32][]*networkingv1.NetworkPolicy {
4847
policiesByPort := make(map[int32][]*networkingv1.NetworkPolicy)
4948
if !targetPodIsolation.IsIngressIsolated() {
50-
policiesByPort[analyzer.portWildcard] = make([]*networkingv1.NetworkPolicy, 0)
49+
policiesByPort[portWildcard] = make([]*networkingv1.NetworkPolicy, 0)
5150
} else {
5251
for i, ingressPolicy := range targetPodIsolation.IngressPolicies {
5352
for _, ingressRule := range ingressPolicy.Spec.Ingress {
5453
if analyzer.ingressRuleAllows(sourcePod, ingressRule, namespaces) {
5554
if len(ingressRule.Ports) == 0 {
56-
policies := policiesByPort[analyzer.portWildcard]
55+
policies := policiesByPort[portWildcard]
5756
if policies == nil {
5857
policies = make([]*networkingv1.NetworkPolicy, 0)
5958
}
6059
policies = append(policies, targetPodIsolation.IngressPolicies[i])
61-
policiesByPort[analyzer.portWildcard] = policies
60+
policiesByPort[portWildcard] = policies
6261
} else {
6362
for _, port := range ingressRule.Ports {
6463
policies := policiesByPort[port.Port.IntVal]
@@ -90,18 +89,18 @@ func (analyzer analyzerImpl) egressPoliciesByPort(targetPod *corev1.Pod, sourceP
9089
namespaces []*corev1.Namespace) map[int32][]*networkingv1.NetworkPolicy {
9190
policiesByPort := make(map[int32][]*networkingv1.NetworkPolicy)
9291
if !sourcePodIsolation.IsEgressIsolated() {
93-
policiesByPort[analyzer.portWildcard] = make([]*networkingv1.NetworkPolicy, 0)
92+
policiesByPort[portWildcard] = make([]*networkingv1.NetworkPolicy, 0)
9493
} else {
9594
for i, egressPolicy := range sourcePodIsolation.EgressPolicies {
9695
for _, egressRule := range egressPolicy.Spec.Egress {
9796
if analyzer.egressRuleAllows(targetPod, egressRule, namespaces) {
9897
if len(egressRule.Ports) == 0 {
99-
policies := policiesByPort[analyzer.portWildcard]
98+
policies := policiesByPort[portWildcard]
10099
if policies == nil {
101100
policies = make([]*networkingv1.NetworkPolicy, 0)
102101
}
103102
policies = append(policies, sourcePodIsolation.EgressPolicies[i])
104-
policiesByPort[analyzer.portWildcard] = policies
103+
policiesByPort[portWildcard] = policies
105104
} else {
106105
for _, port := range egressRule.Ports {
107106
policies := policiesByPort[port.Port.IntVal]
@@ -137,8 +136,8 @@ func (analyzer analyzerImpl) matchPoliciesByPort(ingressPoliciesByPort map[int32
137136
egressPoliciesSet := make(map[*networkingv1.NetworkPolicy]bool)
138137
for ingressPort, ingressPolicies := range ingressPoliciesByPort {
139138
for egressPort, egressPolicies := range egressPoliciesByPort {
140-
if ingressPort == analyzer.portWildcard || egressPort == analyzer.portWildcard || ingressPort == egressPort {
141-
if ingressPort == analyzer.portWildcard {
139+
if ingressPort == portWildcard || egressPort == portWildcard || ingressPort == egressPort {
140+
if ingressPort == portWildcard {
142141
portsSet[egressPort] = true
143142
} else {
144143
portsSet[ingressPort] = true
@@ -152,7 +151,7 @@ func (analyzer analyzerImpl) matchPoliciesByPort(ingressPoliciesByPort map[int32
152151
}
153152
}
154153
}
155-
if portsSet[analyzer.portWildcard] {
154+
if portsSet[portWildcard] {
156155
portsSet = nil
157156
}
158157
var ports []int32

back/analyzer/traffic/allowedroute/allowed_route_analyzer_test.go back/analyzer/traffic/allowedroute/analyzer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"testing"
1212
)
1313

14-
func Test_Analyze(t *testing.T) {
14+
func TestAnalyze(t *testing.T) {
1515
type args struct {
1616
sourcePodIsolation *shared.PodIsolation
1717
targetPodIsolation *shared.PodIsolation
File renamed without changes.

back/analyzer/traffic/traffic_analyzer_test.go back/analyzer/traffic/analyzer_test.go

+9-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package traffic
22

33
import (
4-
"fmt"
54
"github.com/google/go-cmp/cmp"
65
corev1 "k8s.io/api/core/v1"
76
networkingv1 "k8s.io/api/networking/v1"
@@ -14,7 +13,7 @@ import (
1413
"testing"
1514
)
1615

17-
func Test_Analyze(t *testing.T) {
16+
func TestAnalyze(t *testing.T) {
1817
type args struct {
1918
clusterState ClusterState
2019
}
@@ -52,7 +51,7 @@ func Test_Analyze(t *testing.T) {
5251
},
5352
Ports: []int32{80, 443},
5453
}
55-
var tests = []struct {
54+
tests := []struct {
5655
name string
5756
mocks mocks
5857
args args
@@ -144,11 +143,9 @@ func (mock mockPodIsolationAnalyzer) Analyze(pod *corev1.Pod,
144143
return call.returnValue
145144
}
146145
}
147-
fmt.Printf("mockPodIsolationAnalyzer was called with unexpected arguments: \n")
148-
fmt.Printf("\tpod:%s\n", pod)
149-
fmt.Printf("\tnetworkPolicies=%s\n", networkPolicies)
150-
mock.t.FailNow()
151-
panic("unreachable but required to compile")
146+
mock.t.Fatalf("mockPodIsolationAnalyzer was called with unexpected arguments: \n\tpod: %s\n"+
147+
"\tnetworkPolicies: %s\n", pod, networkPolicies)
148+
return nil
152149
}
153150

154151
func createMockPodIsolationAnalyzer(t *testing.T, calls []mockPodIsolationAnalyzerCall) podisolation.Analyzer {
@@ -183,12 +180,10 @@ func (mock mockAllowedRouteAnalyzer) Analyze(sourcePodIsolation *shared.PodIsola
183180
return call.returnValue
184181
}
185182
}
186-
fmt.Printf("mockAllowedRouteAnalyzer was called with unexpected arguments: \n")
187-
fmt.Printf("\tsourcePodIsolation:%s\n", sourcePodIsolation)
188-
fmt.Printf("\ttargetPodIsolation=%s\n", targetPodIsolation)
189-
fmt.Printf("\tnamespaces=%s\n", namespaces)
190-
mock.t.FailNow()
191-
panic("unreachable but required to compile")
183+
mock.t.Fatalf("mockAllowedRouteAnalyzer was called with unexpected arguments: \n"+
184+
"\tsourcePodIsolation: %s\n\ttargetPodIsolation: %s\n\tnamespaces: %s\n", sourcePodIsolation,
185+
targetPodIsolation, namespaces)
186+
return nil
192187
}
193188

194189
func createMockAllowedRouteAnalyzer(t *testing.T, calls []mockAllowedRouteAnalyzerCall) allowedroute.Analyzer {

back/analyzer/traffic/podisolation/pod_isolation_analyzer_test.go back/analyzer/traffic/podisolation/analyzer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"testing"
1010
)
1111

12-
func Test_Analyze(t *testing.T) {
12+
func TestAnalyze(t *testing.T) {
1313
type args struct {
1414
pod *corev1.Pod
1515
networkPolicies []*networkingv1.NetworkPolicy
File renamed without changes.

0 commit comments

Comments
 (0)