Skip to content

Commit 6d8c88a

Browse files
authored
Internal api documentation (#101)
* avoid exporting deploymentConnectivity * update supported versions * inline documentation * package upgrade * example to show in docs * fix lint issue Signed-off-by: Ziv Nevo <[email protected]>
1 parent e3ee9ff commit 6d8c88a

8 files changed

+181
-16
lines changed

SECURITY.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
| Version | Supported |
66
| ------- | ------------------ |
7-
| 1.2.x | :white_check_mark: |
7+
| 1.3.x | :white_check_mark: |
8+
| 1.2.x | :x: |
89
| 1.1.x | :x: |
910
| 1.0.x | :x: |
1011
| < 1.0 | :x: |

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
github.com/json-iterator/go v1.1.12 // indirect
1818
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
1919
github.com/modern-go/reflect2 v1.0.2 // indirect
20-
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
20+
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
2121
golang.org/x/text v0.3.7 // indirect
2222
gopkg.in/inf.v0 v0.9.1 // indirect
2323
gopkg.in/yaml.v2 v2.4.0 // indirect

go.sum

+3-3
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
310310
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
311311
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
312312
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
313-
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
314-
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
313+
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
314+
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
315315
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
316316
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
317317
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -380,7 +380,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
380380
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
381381
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
382382
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
383-
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
383+
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
384384
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
385385
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
386386
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

pkg/controller/error_types.go

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
)
77

8+
// FileProcessingError holds all information about a single error/warning that occurred during
9+
// the discovery and processing of the connectivity of a given K8s-app.
810
type FileProcessingError struct {
911
err error
1012
filePath string
@@ -25,25 +27,30 @@ func newFileProcessingError(origErr error, msg, filePath string, lineNum, docID
2527
return &fpe
2628
}
2729

30+
// Error returns the actual error
2831
func (e *FileProcessingError) Error() error {
2932
return e.err
3033
}
3134

35+
// File returns the file in which the error occurred (or an empty string if no file context is available)
3236
func (e *FileProcessingError) File() string {
3337
return e.filePath
3438
}
3539

40+
// LineNo returns the file's line-number in which the error occurred (or 0 if not applicable)
3641
func (e *FileProcessingError) LineNo() int {
3742
return e.lineNum
3843
}
3944

45+
// DocumentID returns the file's YAML document ID (0-based) in which the error occurred (or an error if not applicable)
4046
func (e *FileProcessingError) DocumentID() (int, error) {
4147
if e.docID < 0 {
4248
return -1, errors.New("no document ID is available for this error")
4349
}
4450
return e.docID, nil
4551
}
4652

53+
// Location returns file location (filename, line-number, document ID) of an error (or an empty string if not applicable)
4754
func (e *FileProcessingError) Location() string {
4855
if e.filePath == "" {
4956
return ""
@@ -59,10 +66,13 @@ func (e *FileProcessingError) Location() string {
5966
return fmt.Sprintf("in file: %s%s", e.File(), suffix)
6067
}
6168

69+
// IsFatal returns whether the error is considered fatal (no further processing is possible)
6270
func (e *FileProcessingError) IsFatal() bool {
6371
return e.fatal
6472
}
6573

74+
// IsFatal returns whether the error is considered severe
75+
// (further processing is possible, but results may not be useable)
6676
func (e *FileProcessingError) IsSevere() bool {
6777
return e.severe
6878
}

pkg/controller/example_test.go

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package controller_test
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
8+
"github.com/np-guard/cluster-topology-analyzer/pkg/controller"
9+
)
10+
11+
func ExamplePoliciesSynthesizer() {
12+
logger := controller.NewDefaultLogger()
13+
synth := controller.NewPoliciesSynthesizer(controller.WithLogger(logger))
14+
15+
netpols, err := synth.PoliciesFromFolderPath("../../tests/k8s_wordpress_example")
16+
if err != nil {
17+
fmt.Fprintf(os.Stderr, "Error synthesizing policies: %v\n", err)
18+
os.Exit(1)
19+
}
20+
buf, _ := json.MarshalIndent(netpols, "", " ")
21+
fmt.Printf("%v\n", string(buf))
22+
// Output:
23+
// [
24+
// {
25+
// "kind": "NetworkPolicy",
26+
// "apiVersion": "networking.k8s.io/v1",
27+
// "metadata": {
28+
// "name": "wordpress-netpol",
29+
// "creationTimestamp": null
30+
// },
31+
// "spec": {
32+
// "podSelector": {
33+
// "matchLabels": {
34+
// "app": "wordpress",
35+
// "tier": "frontend"
36+
// }
37+
// },
38+
// "ingress": [
39+
// {
40+
// "ports": [
41+
// {
42+
// "protocol": "TCP",
43+
// "port": 80
44+
// }
45+
// ]
46+
// }
47+
// ],
48+
// "egress": [
49+
// {
50+
// "ports": [
51+
// {
52+
// "protocol": "TCP",
53+
// "port": 3306
54+
// }
55+
// ],
56+
// "to": [
57+
// {
58+
// "podSelector": {
59+
// "matchLabels": {
60+
// "app": "wordpress",
61+
// "tier": "mysql"
62+
// }
63+
// }
64+
// }
65+
// ]
66+
// },
67+
// {
68+
// "ports": [
69+
// {
70+
// "protocol": "UDP",
71+
// "port": 53
72+
// }
73+
// ]
74+
// }
75+
// ],
76+
// "policyTypes": [
77+
// "Ingress",
78+
// "Egress"
79+
// ]
80+
// }
81+
// },
82+
// {
83+
// "kind": "NetworkPolicy",
84+
// "apiVersion": "networking.k8s.io/v1",
85+
// "metadata": {
86+
// "name": "wordpress-mysql-netpol",
87+
// "creationTimestamp": null
88+
// },
89+
// "spec": {
90+
// "podSelector": {
91+
// "matchLabels": {
92+
// "app": "wordpress",
93+
// "tier": "mysql"
94+
// }
95+
// },
96+
// "ingress": [
97+
// {
98+
// "ports": [
99+
// {
100+
// "protocol": "TCP",
101+
// "port": 3306
102+
// }
103+
// ],
104+
// "from": [
105+
// {
106+
// "podSelector": {
107+
// "matchLabels": {
108+
// "app": "wordpress",
109+
// "tier": "frontend"
110+
// }
111+
// }
112+
// }
113+
// ]
114+
// }
115+
// ],
116+
// "policyTypes": [
117+
// "Ingress",
118+
// "Egress"
119+
// ]
120+
// }
121+
// }
122+
// ]
123+
}

pkg/controller/logger.go

+9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"log"
77
)
88

9+
// Verbosity is an enumerated type for defining the level of verbosity.
910
type Verbosity int
1011

1112
const (
@@ -14,47 +15,55 @@ const (
1415
HighVerbosity
1516
)
1617

18+
// The Logger interface defines the API for loggers in this package.
1719
type Logger interface {
1820
Debugf(format string, o ...interface{})
1921
Infof(format string, o ...interface{})
2022
Warnf(format string, o ...interface{})
2123
Errorf(err error, format string, o ...interface{})
2224
}
2325

26+
// DefaultLogger is the package's built-in logger. It uses log.Default() as the underlying logger.
2427
type DefaultLogger struct {
2528
verbosity Verbosity
2629
l *log.Logger
2730
}
2831

32+
// NewDefaultLogger creates an instance of DefaultLogger with the highest verbosity.
2933
func NewDefaultLogger() *DefaultLogger {
3034
return NewDefaultLoggerWithVerbosity(HighVerbosity)
3135
}
3236

37+
// NewDefaultLoggerWithVerbosity creates an instance of DefaultLogger with a user-defined verbosity.
3338
func NewDefaultLoggerWithVerbosity(verbosity Verbosity) *DefaultLogger {
3439
return &DefaultLogger{
3540
verbosity: verbosity,
3641
l: log.Default(),
3742
}
3843
}
3944

45+
// Debugf writes a debug message to the log (only if DefaultLogger verbosity is set to HighVerbosity)
4046
func (df *DefaultLogger) Debugf(format string, o ...interface{}) {
4147
if df.verbosity == HighVerbosity {
4248
df.l.Printf(format, o...)
4349
}
4450
}
4551

52+
// Infof writes an informative message to the log (only if DefaultLogger verbosity is set to HighVerbosity)
4653
func (df *DefaultLogger) Infof(format string, o ...interface{}) {
4754
if df.verbosity == HighVerbosity {
4855
df.l.Printf(format, o...)
4956
}
5057
}
5158

59+
// Warnf writes a warning message to the log (unless DefaultLogger verbosity is set to LowVerbosity)
5260
func (df *DefaultLogger) Warnf(format string, o ...interface{}) {
5361
if df.verbosity >= MediumVerbosity {
5462
df.l.Printf(format, o...)
5563
}
5664
}
5765

66+
// Errorf writes an error message to the log (regardless of DefaultLogger's verbosity)
5867
func (df *DefaultLogger) Errorf(err error, format string, o ...interface{}) {
5968
df.l.Printf("%s: %v", fmt.Sprintf(format, o...), err)
6069
}

pkg/controller/policies_synthesizer.go

+20
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// The controller package of cluster-topology-analyzer discovers the connectivity of a Kubernetes application
2+
// by analyzing its YAML manifests and looking for network addresses that match. It can output a set of
3+
// discovered connections or even Kubernetes NetworkPolicies to allow only these connections. For more
4+
// information, see https://github.com/np-guard/cluster-topology-analyzer.
15
package controller
26

37
import (
@@ -6,27 +10,38 @@ import (
610
"github.com/np-guard/cluster-topology-analyzer/pkg/common"
711
)
812

13+
// A PoliciesSynthesizer provides API to recursively scan a directory for Kubernetes resources
14+
// and extract the required connectivity between the workloads of the K8s application managed in this directory.
15+
// It is possible to get either a slice with all the discovered connections or a slice with K8s NetworkPolicies
16+
// that allow only the discovered connections and nothing more.
917
type PoliciesSynthesizer struct {
1018
logger Logger
1119
stopOnError bool
1220

1321
errors []FileProcessingError
1422
}
1523

24+
// PoliciesSynthesizerOption is the type for specifying options for PoliciesSynthesizer,
25+
// using Golang's Options Pattern (https://golang.cafe/blog/golang-functional-options-pattern.html).
1626
type PoliciesSynthesizerOption func(*PoliciesSynthesizer)
1727

28+
// WithLogger is a functional option which sets the logger for a PoliciesSynthesizer to use.
29+
// The provided logger must conform with the package's Logger interface.
1830
func WithLogger(logger Logger) PoliciesSynthesizerOption {
1931
return func(p *PoliciesSynthesizer) {
2032
p.logger = logger
2133
}
2234
}
2335

36+
// WithStopOnError is a functional option which directs PoliciesSynthesizer to stop any processing after the
37+
// first severe error.
2438
func WithStopOnError() PoliciesSynthesizerOption {
2539
return func(p *PoliciesSynthesizer) {
2640
p.stopOnError = true
2741
}
2842
}
2943

44+
// NewPoliciesSynthesizer creates a new instance of PoliciesSynthesizer, and applies the provided functional options.
3045
func NewPoliciesSynthesizer(options ...PoliciesSynthesizerOption) *PoliciesSynthesizer {
3146
// object with default behavior options
3247
ps := &PoliciesSynthesizer{
@@ -41,10 +56,13 @@ func NewPoliciesSynthesizer(options ...PoliciesSynthesizerOption) *PoliciesSynth
4156
return ps
4257
}
4358

59+
// Errors returns a slice of FileProcessingError with all warnings and errors encountered during processing.
4460
func (ps *PoliciesSynthesizer) Errors() []FileProcessingError {
4561
return ps.errors
4662
}
4763

64+
// PoliciesFromFolderPath returns a slice of Kubernetes NetworkPolicies that allow only the connections discovered
65+
// while processing K8s resources under the provided directory or one of its subdirectories (recursively).
4866
func (ps *PoliciesSynthesizer) PoliciesFromFolderPath(dirPath string) ([]*networking.NetworkPolicy, error) {
4967
connections, errs := extractConnections(dirPath, ps.stopOnError)
5068
policies := []*networking.NetworkPolicy{}
@@ -60,6 +78,8 @@ func (ps *PoliciesSynthesizer) PoliciesFromFolderPath(dirPath string) ([]*networ
6078
return policies, nil
6179
}
6280

81+
// ConnectionsFromFolderPath returns a slice of Connections, listing the connections discovered
82+
// while processing K8s resources under the provided directory or one of its subdirectories (recursively).
6383
func (ps *PoliciesSynthesizer) ConnectionsFromFolderPath(dirPath string) ([]*common.Connections, error) {
6484
connections, errs := extractConnections(dirPath, ps.stopOnError)
6585
ps.errors = errs

0 commit comments

Comments
 (0)