Skip to content

Commit e84affd

Browse files
committed
feat: packet traces feature for Retina CLI
1 parent 13261f3 commit e84affd

20 files changed

+135
-151
lines changed

cli/cmd/root.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package cmd
44

55
import (
66
"encoding/json"
7-
"io/ioutil"
7+
"os"
88

99
"github.com/microsoft/retina/pkg/client"
1010
"github.com/microsoft/retina/pkg/log"
@@ -33,7 +33,7 @@ func NewRootCmd() *cobra.Command {
3333
rootCmd := &cobra.Command{
3434
PersistentPreRun: func(cmd *cobra.Command, args []string) {
3535
var config Config
36-
file, _ := ioutil.ReadFile(ClientConfigPath)
36+
file, _ := os.ReadFile(ClientConfigPath)
3737
_ = json.Unmarshal([]byte(file), &config)
3838
RetinaClient = client.NewRetinaClient(config.RetinaEndpoint)
3939
},

cli/cmd/trace.go cli/cmd/trace/trace.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
3-
package cmd
3+
package trace
44

55
import (
6+
retinacmd "github.com/microsoft/retina/cli/cmd"
67
"github.com/spf13/cobra"
78
)
89

@@ -19,9 +20,13 @@ func getTrace() *cobra.Command {
1920
cmd := &cobra.Command{
2021
Use: "get",
2122
Short: "Retrieve network trace results with operation ID",
22-
RunE: func(cmd *cobra.Command, args []string) error {
23+
RunE: func(cmd *cobra.Command, _ []string) error {
2324
operationID, _ := cmd.Flags().GetString("operationID")
24-
return RetinaClient.GetTrace(operationID)
25+
err := retinacmd.RetinaClient.GetTrace(operationID)
26+
if err != nil {
27+
return err
28+
}
29+
return nil
2530
},
2631
}
2732
cmd.Flags().String("operationID", "", "Network Trace Operation ID")

cli/main.go

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
func main() {
1111
rootCmd := cmd.NewRootCmd()
12+
// rootCmd.AddCommand(trace.TraceCmd())
1213
rootCmd.AddCommand(capture.CaptureCmd())
1314
rootCmd.AddCommand(cmd.VersionCmd())
1415
rootCmd.Execute() //nolint:errcheck

deploy/registercrd.go

+27-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const (
1818
RetinaCapturesYAMLpath = "retina.sh_captures.yaml"
1919
RetinaEndpointsYAMLpath = "retina.sh_retinaendpoints.yaml"
2020
MetricsConfigurationYAMLpath = "retina.sh_metricsconfigurations.yaml"
21+
TracesConfigurationYAMLpath = "retina.sh_tracesconfigurations.yaml"
2122
)
2223

2324
//go:embed manifests/controller/helm/retina/crds/retina.sh_captures.yaml
@@ -29,6 +30,9 @@ var RetinaEndpointsYAML []byte
2930
//go:embed manifests/controller/helm/retina/crds/retina.sh_metricsconfigurations.yaml
3031
var MetricsConfgurationYAML []byte
3132

33+
//go:embed manifests/controller/helm/retina/crds/retina.sh_tracesconfigurations.yaml
34+
var TracesConfigurationYAML []byte
35+
3236
func GetRetinaCapturesCRD() (*apiextensionsv1.CustomResourceDefinition, error) {
3337
retinaCapturesCRD := &apiextensionsv1.CustomResourceDefinition{}
3438
if err := yaml.Unmarshal(RetinaCapturesYAML, &retinaCapturesCRD); err != nil {
@@ -55,7 +59,21 @@ func GetRetinaMetricsConfigurationCRD() (*apiextensionsv1.CustomResourceDefiniti
5559
return retinaMetricsConfigurationCRD, nil
5660
}
5761

58-
func InstallOrUpdateCRDs(ctx context.Context, enableRetinaEndpoint bool, apiExtensionsClient apiextv1.ApiextensionsV1Interface) (map[string]*apiextensionsv1.CustomResourceDefinition, error) {
62+
func GetRetinaTracesConfigurationCRD() (*apiextensionsv1.CustomResourceDefinition, error) {
63+
retinaTracesConfigurationCRD := &apiextensionsv1.CustomResourceDefinition{}
64+
if err := yaml.Unmarshal(TracesConfigurationYAML, &retinaTracesConfigurationCRD); err != nil {
65+
return nil, errors.Wrap(err, "error unmarshalling embedded tracesconfiguration")
66+
}
67+
return retinaTracesConfigurationCRD, nil
68+
}
69+
70+
func InstallOrUpdateCRDs(
71+
ctx context.Context,
72+
enableRetinaEndpoint bool,
73+
apiExtensionsClient apiextv1.ApiextensionsV1Interface,
74+
enableTrace bool,
75+
) (map[string]*apiextensionsv1.CustomResourceDefinition, error) {
76+
5977
crds := make(map[string]*apiextensionsv1.CustomResourceDefinition, 4)
6078

6179
retinaCapture, err := GetRetinaCapturesCRD()
@@ -78,6 +96,14 @@ func InstallOrUpdateCRDs(ctx context.Context, enableRetinaEndpoint bool, apiExte
7896
}
7997
crds[retinaMetricsConfiguration.GetObjectMeta().GetName()] = retinaMetricsConfiguration
8098

99+
if enableTrace {
100+
retinaTracesConfiguration, err := GetRetinaTracesConfigurationCRD()
101+
if err != nil {
102+
return nil, err
103+
}
104+
crds[retinaTracesConfiguration.GetObjectMeta().GetName()] = retinaTracesConfiguration
105+
}
106+
81107
for name, crd := range crds {
82108
current, err := apiExtensionsClient.CustomResourceDefinitions().Create(ctx, crd, v1.CreateOptions{})
83109
if apierrors.IsAlreadyExists(err) {

deploy/registercrd_test.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func TestGetCRD(t *testing.T) {
2323
require.FileExists(t, fmt.Sprintf(full, RetinaCapturesYAMLpath))
2424
require.FileExists(t, fmt.Sprintf(full, RetinaEndpointsYAMLpath))
2525
require.FileExists(t, fmt.Sprintf(full, MetricsConfigurationYAMLpath))
26+
require.FileExists(t, fmt.Sprintf(full, TracesConfigurationYAMLpath))
2627

2728
capture, err := GetRetinaCapturesCRD()
2829
require.NoError(t, err)
@@ -38,12 +39,18 @@ func TestGetCRD(t *testing.T) {
3839
require.NoError(t, err)
3940
require.NotNil(t, metrics)
4041
require.NotEmpty(t, metrics.TypeMeta.Kind)
42+
43+
traces, err := GetRetinaTracesConfigurationCRD()
44+
require.NoError(t, err)
45+
require.NotNil(t, traces)
46+
require.NotEmpty(t, traces.TypeMeta.Kind)
4147
}
4248

4349
func TestInstallOrUpdateCRDs(t *testing.T) {
4450
capture, _ := GetRetinaCapturesCRD()
4551
endpoint, _ := GetRetinaEndpointCRD()
4652
metrics, _ := GetRetinaMetricsConfigurationCRD()
53+
traces, _ := GetRetinaTracesConfigurationCRD()
4754

4855
tests := []struct {
4956
name string
@@ -58,6 +65,7 @@ func TestInstallOrUpdateCRDs(t *testing.T) {
5865
"captures.retina.sh": capture,
5966
"retinaendpoints.retina.sh": endpoint,
6067
"metricsconfigurations.retina.sh": metrics,
68+
"tracesconfigurations.retina.sh": traces,
6169
},
6270
},
6371
{
@@ -66,6 +74,7 @@ func TestInstallOrUpdateCRDs(t *testing.T) {
6674
want: map[string]*apiextensionsv1.CustomResourceDefinition{
6775
"captures.retina.sh": capture,
6876
"metricsconfigurations.retina.sh": metrics,
77+
"tracesconfigurations.retina.sh": traces,
6978
},
7079
},
7180
}
@@ -75,7 +84,7 @@ func TestInstallOrUpdateCRDs(t *testing.T) {
7584
apiExtensionsClient := &apiextv1fake.FakeApiextensionsV1{
7685
Fake: &kubeClient.Fake,
7786
}
78-
got, err := InstallOrUpdateCRDs(context.Background(), tt.enableRetinaEndpoint, apiExtensionsClient)
87+
got, err := InstallOrUpdateCRDs(context.Background(), tt.enableRetinaEndpoint, apiExtensionsClient, false)
7988
if (err != nil) != tt.wantErr {
8089
require.NoError(t, err)
8190
return

docs/CRDs/TracesConfiguration.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# TraceConfiguration
2+
3+
> **Note:** This feature is currently under experimental development.
4+
5+
## Overview
6+
7+
The `TraceConfiguration` CustomResourceDefinition (CRD) introduces a custom resource named `TraceConfiguration` that enables users to configure packet traces in a Kubernetes cluster. Packet traces can be tailored to specific use cases, offering the flexibility to capture detailed network data for debugging or continuous streaming of traces for security purposes.
8+
9+
## CRD Specification
10+
11+
The full specification for the `MetricsConfiguration` CRD can be found in the [TraceConfiguration CRD](https://github.com/microsoft/retina/blob/main/deploy/manifests/controller/helm/retina/crds/retina.sh_tracesconfigurations.yaml) file.
12+
13+
The `TraceConfiguration` CRD is defined with the following specifications:
14+
15+
- **API Group:** retina.sh
16+
- **API Version:** v1alpha1
17+
- **Kind:** TraceConfiguration
18+
- **Plural:** traceconfigurations
19+
- **Singular:** traceconfiguration
20+
- **Scope:** Namespaced
21+
22+
### Fields
23+
24+
- **spec.traceConfigurations:** Specifies the detailed configuration options for packet tracing. It includes the following properties:
25+
- `captureLevel`: Specifies the capture level, which can be set to `allPackets` or `firstPacket` (default).
26+
- `includeLayer7Data`: Indicates whether layer 7 data (HTTP, DNS, TLS) should be included in the trace (default is `false`).
27+
- `from`: Specifies the source entities from which packets will be captured, including IP blocks, namespaces, pods, and more.
28+
- `to`: Specifies the destination entities to which packets will be captured, including IP blocks, services, and more.
29+
- `ports`: Specifies the ports and protocols to capture packets for.
30+
31+
- **spec.tracePoints:** Specifies the types of trace points to capture, such as pod, nodeToPod, and nodeToNetwork.
32+
33+
- **spec.outputConfiguration:** Specifies the output destination and connection configuration for trace data. It includes the following properties:
34+
- `destination`: Specifies the destination for trace data, which can be `stdout`, `azuretable`, `loganalytics`, or `opentelemetry`.
35+
- `connectionConfiguration`: Specifies connection-related configuration options.
36+
37+
- **status:** Describes the status of the trace configuration, including the current state, reason, and accepted specification.
38+
39+
## Usage
40+
41+
### Configuring Packet Traces
42+
43+
To configure packet traces, create a YAML manifest file with the desired specifications and apply it to the cluster using `kubectl apply`:
44+
45+
```yaml
46+
apiVersion: retina.sh/v1alpha1
47+
kind: TraceConfiguration
48+
metadata:
49+
name: example-trace-configuration
50+
spec:
51+
traceConfigurations:
52+
- captureLevel: firstPacket
53+
includeLayer7Data: true
54+
from:
55+
- ipBlock:
56+
cidr: 10.0.0.0/16
57+
except:
58+
- 10.0.0.5
59+
to:
60+
- namespaceSelector:
61+
label: value
62+
ports:
63+
- port: "80"
64+
protocol: TCP
65+
tracePoints:
66+
- pod
67+
- nodeToPod
68+
outputConfiguration:
69+
destination: stdout
70+
```

operator/cache/types.go

+5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ type MetricsConfigurationCacheObject struct {
2020
MetricsConfiguration *retinav1alpha1.MetricsConfiguration
2121
}
2222

23+
type TraceConfigurationCacheObject struct {
24+
Key string // cache.MetaNamespaceKeyFunc
25+
TraceConfiguration *retinav1alpha1.TraceConfiguration
26+
}
27+
2328
type RetinaEndpoint struct {
2429
sync.RWMutex
2530
Name string

operator/config/config.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ type OperatorConfig struct {
1010
LogLevel string `yaml:"logLevel"`
1111
// EnableRetinaEndpoint indicates whether to enable RetinaEndpoint
1212
EnableRetinaEndpoint bool `yaml:"enableRetinaEndpoint"`
13-
RemoteContext bool `yaml:"remoteContext"`
13+
// EnableTrace indicates whether to enable trace. This is a WIP feature.
14+
EnableTrace bool `yaml:"enableTrace"`
15+
RemoteContext bool `yaml:"remoteContext"`
1416
}

operator/main.go

+1-17
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,3 @@
1-
/*
2-
Copyright 2023.
3-
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
7-
8-
http://www.apache.org/licenses/LICENSE-2.0
9-
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
15-
*/
16-
171
package main
182

193
import (
@@ -146,7 +130,7 @@ func main() {
146130

147131
if oconfig.InstallCRDs {
148132
mainLogger.Sugar().Infof("Installing CRDs")
149-
crds, err := deploy.InstallOrUpdateCRDs(ctx, oconfig.EnableRetinaEndpoint, clientset)
133+
crds, err := deploy.InstallOrUpdateCRDs(ctx, oconfig.EnableRetinaEndpoint, clientset, oconfig.EnableTrace) //nolint // shadowing is fine here
150134
if err != nil {
151135
mainLogger.Error("unable to register CRDs", zap.Error(err))
152136
os.Exit(1)

pkg/controllers/daemon/metricsconfiguration/metricsconfiguration_controller.go

-13
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
1-
/*
2-
Copyright 2023.
3-
Licensed under the Apache License, Version 2.0 (the "License");
4-
you may not use this file except in compliance with the License.
5-
You may obtain a copy of the License at
6-
http://www.apache.org/licenses/LICENSE-2.0
7-
Unless required by applicable law or agreed to in writing, software
8-
distributed under the License is distributed on an "AS IS" BASIS,
9-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10-
See the License for the specific language governing permissions and
11-
limitations under the License.
12-
*/
13-
141
package metricsconfigurationcontroller
152

163
import (

pkg/controllers/daemon/metricsconfiguration/metricsconfiguration_controller_test.go

-13
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
1-
/*
2-
Copyright 2023.
3-
Licensed under the Apache License, Version 2.0 (the "License");
4-
you may not use this file except in compliance with the License.
5-
You may obtain a copy of the License at
6-
http://www.apache.org/licenses/LICENSE-2.0
7-
Unless required by applicable law or agreed to in writing, software
8-
distributed under the License is distributed on an "AS IS" BASIS,
9-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10-
See the License for the specific language governing permissions and
11-
limitations under the License.
12-
*/
13-
141
package metricsconfigurationcontroller
152

163
import (

pkg/controllers/operator/metricsconfiguration/metricsconfiguration_controller.go

-13
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
1-
/*
2-
Copyright 2023.
3-
Licensed under the Apache License, Version 2.0 (the "License");
4-
you may not use this file except in compliance with the License.
5-
You may obtain a copy of the License at
6-
http://www.apache.org/licenses/LICENSE-2.0
7-
Unless required by applicable law or agreed to in writing, software
8-
distributed under the License is distributed on an "AS IS" BASIS,
9-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10-
See the License for the specific language governing permissions and
11-
limitations under the License.
12-
*/
13-
141
package metricsconfigurationcontroller
152

163
import (

pkg/controllers/operator/metricsconfiguration/metricsconfiguration_controller_test.go

-13
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
1-
/*
2-
Copyright 2023.
3-
Licensed under the Apache License, Version 2.0 (the "License");
4-
you may not use this file except in compliance with the License.
5-
You may obtain a copy of the License at
6-
http://www.apache.org/licenses/LICENSE-2.0
7-
Unless required by applicable law or agreed to in writing, software
8-
distributed under the License is distributed on an "AS IS" BASIS,
9-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10-
See the License for the specific language governing permissions and
11-
limitations under the License.
12-
*/
13-
141
package metricsconfigurationcontroller
152

163
import (

pkg/controllers/operator/pod/pod_controller.go

-16
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,3 @@
1-
/*
2-
Copyright 2023.
3-
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
7-
8-
http://www.apache.org/licenses/LICENSE-2.0
9-
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
15-
*/
16-
171
package podcontroller
182

193
import (

pkg/controllers/operator/pod/pod_controller_test.go

-16
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,3 @@
1-
/*
2-
Copyright 2023.
3-
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
7-
8-
http://www.apache.org/licenses/LICENSE-2.0
9-
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
15-
*/
16-
171
package podcontroller
182

193
import (

pkg/controllers/operator/retinaendpoint/retinaendpoint_controller.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func New(client client.Client, podchannel chan cache.PodCacheObject) *RetinaEndp
5252

5353
// NOTE(mainrerd): Chances are that pod cache channel lost pods events during controller manager restart, we need to
5454
// have full-set reconciliation to make sure all RetinaEndpoints are reconciled to Pods.
55-
// when a pod reaches here, it indicates that there is a metricsconfiguration that references it,
55+
// when a pod reaches here, it indicates that there is a metricsconfiguration (or tracesconfiguration if enabled) that references it,
5656
// or doesn't and a RetinaEndpoint needs to be created or updated.
5757
// This is a blocking function, and will wait on the pod channel until a pod is received.
5858
func (r *RetinaEndpointReconciler) ReconcilePod(pctx context.Context) {

0 commit comments

Comments
 (0)