From 717b8b2061d2862b7d3ad19f252a340ffbfff42e Mon Sep 17 00:00:00 2001 From: Smuu <18609909+Smuu@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:24:36 +0100 Subject: [PATCH 1/8] feat: add support for bittwister Signed-off-by: Smuu <18609909+Smuu@users.noreply.github.com> --- pkg/k8s/k8s_pod.go | 48 ++++----- pkg/knuu/instance.go | 189 +++++++++++++++++++++++++++++++----- pkg/knuu/instance_helper.go | 131 ++++++++++++++++++++----- 3 files changed, 296 insertions(+), 72 deletions(-) diff --git a/pkg/k8s/k8s_pod.go b/pkg/k8s/k8s_pod.go index 6501b90..9471f0a 100644 --- a/pkg/k8s/k8s_pod.go +++ b/pkg/k8s/k8s_pod.go @@ -90,19 +90,20 @@ func NewFile(source, dest string) *File { // ContainerConfig contains the specifications for creating a new Container object type ContainerConfig struct { - Name string // Name to assign to the Container - Image string // Name of the container image to use for the container - Command []string // Command to run in the container - Args []string // Arguments to pass to the command in the container - Env map[string]string // Environment variables to set in the container - Volumes []*Volume // Volumes to mount in the Pod - MemoryRequest string // Memory request for the container - MemoryLimit string // Memory limit for the container - CPURequest string // CPU request for the container - LivenessProbe *v1.Probe // Liveness probe for the container - ReadinessProbe *v1.Probe // Readiness probe for the container - StartupProbe *v1.Probe // Startup probe for the container - Files []*File // Files to add to the Pod + Name string // Name to assign to the Container + Image string // Name of the container image to use for the container + Command []string // Command to run in the container + Args []string // Arguments to pass to the command in the container + Env map[string]string // Environment variables to set in the container + Volumes []*Volume // Volumes to mount in the Pod + MemoryRequest string // Memory request for the container + MemoryLimit string // Memory limit for the container + CPURequest string // CPU request for the container + LivenessProbe *v1.Probe // Liveness probe for the container + ReadinessProbe *v1.Probe // Readiness probe for the container + StartupProbe *v1.Probe // Startup probe for the container + Files []*File // Files to add to the Pod + SecurityContext *v1.SecurityContext // Security context for the container } // PodConfig contains the specifications for creating a new Pod object @@ -439,16 +440,17 @@ func prepareContainer(config ContainerConfig) (v1.Container, error) { } return v1.Container{ - Name: config.Name, - Image: config.Image, - Command: config.Command, - Args: config.Args, - Env: podEnv, - VolumeMounts: containerVolumes, - Resources: resources, - LivenessProbe: config.LivenessProbe, - ReadinessProbe: config.ReadinessProbe, - StartupProbe: config.StartupProbe, + Name: config.Name, + Image: config.Image, + Command: config.Command, + Args: config.Args, + Env: podEnv, + VolumeMounts: containerVolumes, + Resources: resources, + LivenessProbe: config.LivenessProbe, + ReadinessProbe: config.ReadinessProbe, + StartupProbe: config.StartupProbe, + SecurityContext: config.SecurityContext, }, nil } diff --git a/pkg/knuu/instance.go b/pkg/knuu/instance.go index ca81c66..ca191e3 100644 --- a/pkg/knuu/instance.go +++ b/pkg/knuu/instance.go @@ -48,6 +48,30 @@ type ObsyConfig struct { otlpPassword string } +// SecurityContext represents the security settings for a container +type SecurityContext struct { + // Privileged indicates whether the container should be run in privileged mode + privileged bool + + // CapabilitiesAdd is the list of capabilities to add to the container + capabilitiesAdd []string +} + +// NetworkConfig represents the configuration for the network +type NetworkConfig struct { + // bandwidth is the bandwidth limit in bps (e.g. 1000 for 1Kbps) + bandwidth int + + // jitter is the network jitter in milliseconds (e.g. 10 for 10ms) + jitter int + + // latency is the network latency in milliseconds (e.g. 100 for 100ms) + latency int + + // packetLoss is the network packet loss rate (e.g. 10 for 10% packet loss) + packetLoss int +} + // Instance represents a instance type Instance struct { name string @@ -77,6 +101,8 @@ type Instance struct { sidecars []*Instance fsGroup int64 obsyConfig *ObsyConfig + securityContext *SecurityContext + networkConfig *NetworkConfig } // NewInstance creates a new instance of the Instance struct @@ -101,31 +127,43 @@ func NewInstance(name string) (*Instance, error) { otlpPassword: "", jaegerEndpoint: "", } + securityContext := &SecurityContext{ + privileged: false, + capabilitiesAdd: make([]string, 0), + } + networkConfig := &NetworkConfig{ + bandwidth: 0, + jitter: 0, + latency: 0, + packetLoss: 0, + } // Create the instance return &Instance{ - name: name, - k8sName: k8sName, - imageName: "", - state: None, - instanceType: BasicInstance, - portsTCP: make([]int, 0), - portsUDP: make([]int, 0), - command: make([]string, 0), - args: make([]string, 0), - env: make(map[string]string), - volumes: make([]*k8s.Volume, 0), - memoryRequest: "", - memoryLimit: "", - cpuRequest: "", - policyRules: make([]rbacv1.PolicyRule, 0), - livenessProbe: nil, - readinessProbe: nil, - startupProbe: nil, - files: make([]*k8s.File, 0), - isSidecar: false, - parentInstance: nil, - sidecars: make([]*Instance, 0), - obsyConfig: obsyConfig, + name: name, + k8sName: k8sName, + imageName: "", + state: None, + instanceType: BasicInstance, + portsTCP: make([]int, 0), + portsUDP: make([]int, 0), + command: make([]string, 0), + args: make([]string, 0), + env: make(map[string]string), + volumes: make([]*k8s.Volume, 0), + memoryRequest: "", + memoryLimit: "", + cpuRequest: "", + policyRules: make([]rbacv1.PolicyRule, 0), + livenessProbe: nil, + readinessProbe: nil, + startupProbe: nil, + files: make([]*k8s.File, 0), + isSidecar: false, + parentInstance: nil, + sidecars: make([]*Instance, 0), + obsyConfig: obsyConfig, + securityContext: securityContext, + networkConfig: networkConfig, }, nil } @@ -784,6 +822,41 @@ func (i *Instance) SetJaegerExporter(endpoint string) error { return nil } +// SetPrivileged sets the privileged status for the instance +// This function can only be called in the state 'Preparing' or 'Committed' +func (i *Instance) SetPrivileged(privileged bool) error { + if !i.IsInState(Preparing, Committed) { + return fmt.Errorf("setting privileged is only allowed in state 'Preparing' or 'Committed'. Current state is '%s'", i.state.String()) + } + i.securityContext.privileged = privileged + logrus.Debugf("Set privileged to '%t' for instance '%s'", privileged, i.name) + return nil +} + +// AddCapability adds a capability to the instance +// This function can only be called in the state 'Preparing' or 'Committed' +func (i *Instance) AddCapability(capability string) error { + if !i.IsInState(Preparing, Committed) { + return fmt.Errorf("adding capability is only allowed in state 'Preparing' or 'Committed'. Current state is '%s'", i.state.String()) + } + i.securityContext.capabilitiesAdd = append(i.securityContext.capabilitiesAdd, capability) + logrus.Debugf("Added capability '%s' to instance '%s'", capability, i.name) + return nil +} + +// AddCapabilities adds multiple capabilities to the instance +// This function can only be called in the state 'Preparing' or 'Committed' +func (i *Instance) AddCapabilities(capabilities []string) error { + if !i.IsInState(Preparing, Committed) { + return fmt.Errorf("adding capabilities is only allowed in state 'Preparing' or 'Committed'. Current state is '%s'", i.state.String()) + } + for _, capability := range capabilities { + i.securityContext.capabilitiesAdd = append(i.securityContext.capabilitiesAdd, capability) + logrus.Debugf("Added capability '%s' to instance '%s'", capability, i.name) + } + return nil +} + // StartWithoutWait starts the instance without waiting for it to be ready // This function can only be called in the state 'Committed' or 'Stopped' func (i *Instance) StartWithoutWait() error { @@ -808,6 +881,12 @@ func (i *Instance) StartWithoutWait() error { return fmt.Errorf("error adding OpenTelemetry collector sidecar for instance '%s': %w", i.k8sName, err) } } + // check if networking is configured and if so, add the corresponding sidecar + if i.isNetworkConfigSet() { + if err := i.addNetworkConfigSidecar(); err != nil { + return fmt.Errorf("error adding network sidecar for instance '%s': %w", i.k8sName, err) + } + } if err := i.deployResources(); err != nil { return fmt.Errorf("error deploying resources for instance '%s': %w", i.k8sName, err) @@ -896,6 +975,70 @@ func (i *Instance) DisableNetwork() error { return nil } +// SetBandwidthLimit sets the bandwidth limit of the instance +// bandwidth limit in bps (e.g. 1000 for 1Kbps) +// Currently, only one of bandwidth, jitter, latency or packet loss can be set +// This function can only be called in the state 'Commited' +func (i *Instance) SetBandwidthLimit(limit int) error { + if !i.IsInState(Committed) { + return fmt.Errorf("setting bandwidth limit is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + } + if i.isNetworkConfigSet() { + return fmt.Errorf("setting bandwidth limit is not allowed if network config is already set") + } + i.networkConfig.bandwidth = limit + logrus.Debugf("Set bandwidth limit to '%d' in instance '%s'", limit, i.name) + return nil +} + +// SetJitter sets the jitter of the instance +// jitter in ms (e.g. 1000 for 1s) +// Currently, only one of bandwidth, jitter, latency or packet loss can be set +// This function can only be called in the state 'Commited' +func (i *Instance) SetJitter(jitter int) error { + if !i.IsInState(Committed) { + return fmt.Errorf("setting jitter is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + } + if i.isNetworkConfigSet() { + return fmt.Errorf("setting jitter is not allowed if network config is already set") + } + i.networkConfig.jitter = jitter + logrus.Debugf("Set jitter to '%d' in instance '%s'", jitter, i.name) + return nil +} + +// SetLatency sets the latency of the instance +// latency in ms (e.g. 1000 for 1s) +// Currently, only one of bandwidth, jitter, latency or packet loss can be set +// This function can only be called in the state 'Commited' +func (i *Instance) SetLatency(latency int) error { + if !i.IsInState(Committed) { + return fmt.Errorf("setting latency is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + } + if i.isNetworkConfigSet() { + return fmt.Errorf("setting latency is not allowed if network config is already set") + } + i.networkConfig.latency = latency + logrus.Debugf("Set latency to '%d' in instance '%s'", latency, i.name) + return nil +} + +// SetPacketLoss sets the packet loss of the instance +// packet loss in percent (e.g. 10 for 10%) +// Currently, only one of bandwidth, jitter, latency or packet loss can be set +// This function can only be called in the state 'Commited' +func (i *Instance) SetPacketLoss(packetLoss int) error { + if !i.IsInState(Committed) { + return fmt.Errorf("setting packet loss is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + } + if i.isNetworkConfigSet() { + return fmt.Errorf("setting packet loss is not allowed if network config is already set") + } + i.networkConfig.packetLoss = packetLoss + logrus.Debugf("Set packet loss to '%d' in instance '%s'", packetLoss, i.name) + return nil +} + // EnableNetwork enables the network of the instance // This function can only be called in the state 'Started' func (i *Instance) EnableNetwork() error { diff --git a/pkg/knuu/instance_helper.go b/pkg/knuu/instance_helper.go index b339e8f..6886277 100644 --- a/pkg/knuu/instance_helper.go +++ b/pkg/knuu/instance_helper.go @@ -11,6 +11,7 @@ import ( "github.com/celestiaorg/knuu/pkg/k8s" "github.com/google/uuid" "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" ) @@ -322,6 +323,12 @@ func (i *Instance) cloneWithSuffix(suffix string) *Instance { clonedSidecars[i] = sidecar.cloneWithSuffix(suffix) } + // Deep copy of networkConfig to ensure cloned instance has its own copy + clonedNetworkConfig := *i.networkConfig + + // Deep copy of securityContext to ensure cloned instance has its own copy + clonedSecurityContext := *i.securityContext + return &Instance{ name: i.name + suffix, k8sName: i.k8sName + suffix, @@ -348,6 +355,8 @@ func (i *Instance) cloneWithSuffix(suffix string) *Instance { parentInstance: nil, sidecars: clonedSidecars, obsyConfig: i.obsyConfig, + securityContext: &clonedSecurityContext, + networkConfig: &clonedNetworkConfig, } } @@ -411,41 +420,66 @@ func (i *Instance) addFileToBuilder(src, dest, chown string) error { return nil } +// prepareSecurityContext creates a v1.SecurityContext from a given SecurityContext. +func prepareSecurityContext(config *SecurityContext) *v1.SecurityContext { + securityContext := &v1.SecurityContext{} + + if config != nil { + if config.privileged { + securityContext.Privileged = &config.privileged + } + if len(config.capabilitiesAdd) > 0 { + capabilities := make([]v1.Capability, len(config.capabilitiesAdd)) + for i, cap := range config.capabilitiesAdd { + capabilities[i] = v1.Capability(cap) + } + securityContext.Capabilities = &v1.Capabilities{ + Add: capabilities, + } + } + } + + return securityContext +} + // prepareConfig prepares the config for the instance func (i *Instance) prepareStatefulSetConfig() k8s.StatefulSetConfig { + // Generate the container configuration containerConfig := k8s.ContainerConfig{ - Name: i.k8sName, - Image: i.imageName, - Command: i.command, - Args: i.args, - Env: i.env, - Volumes: i.volumes, - MemoryRequest: i.memoryRequest, - MemoryLimit: i.memoryLimit, - CPURequest: i.cpuRequest, - LivenessProbe: i.livenessProbe, - ReadinessProbe: i.readinessProbe, - StartupProbe: i.startupProbe, - Files: i.files, + Name: i.k8sName, + Image: i.imageName, + Command: i.command, + Args: i.args, + Env: i.env, + Volumes: i.volumes, + MemoryRequest: i.memoryRequest, + MemoryLimit: i.memoryLimit, + CPURequest: i.cpuRequest, + LivenessProbe: i.livenessProbe, + ReadinessProbe: i.readinessProbe, + StartupProbe: i.startupProbe, + Files: i.files, + SecurityContext: prepareSecurityContext(i.securityContext), } // Generate the sidecar configurations sidecarConfigs := make([]k8s.ContainerConfig, 0) for _, sidecar := range i.sidecars { sidecarConfigs = append(sidecarConfigs, k8s.ContainerConfig{ - Name: sidecar.k8sName, - Image: sidecar.imageName, - Command: sidecar.command, - Args: sidecar.args, - Env: sidecar.env, - Volumes: sidecar.volumes, - MemoryRequest: sidecar.memoryRequest, - MemoryLimit: sidecar.memoryLimit, - CPURequest: sidecar.cpuRequest, - LivenessProbe: sidecar.livenessProbe, - ReadinessProbe: sidecar.readinessProbe, - StartupProbe: sidecar.startupProbe, - Files: sidecar.files, + Name: sidecar.k8sName, + Image: sidecar.imageName, + Command: sidecar.command, + Args: sidecar.args, + Env: sidecar.env, + Volumes: sidecar.volumes, + MemoryRequest: sidecar.memoryRequest, + MemoryLimit: sidecar.memoryLimit, + CPURequest: sidecar.cpuRequest, + LivenessProbe: sidecar.livenessProbe, + ReadinessProbe: sidecar.readinessProbe, + StartupProbe: sidecar.startupProbe, + Files: sidecar.files, + SecurityContext: prepareSecurityContext(sidecar.securityContext), }) } // Generate the pod configuration @@ -514,6 +548,11 @@ func (i *Instance) isObservabilityEnabled() bool { return i.obsyConfig.otlpPort != 0 || i.obsyConfig.prometheusPort != 0 || i.obsyConfig.jaegerGrpcPort != 0 || i.obsyConfig.jaegerThriftCompactPort != 0 || i.obsyConfig.jaegerThriftHttpPort != 0 } +// isNetworkConfigSet returns true if any network config value is set +func (i *Instance) isNetworkConfigSet() bool { + return i.networkConfig.bandwidth != 0 || i.networkConfig.jitter != 0 || i.networkConfig.latency != 0 || i.networkConfig.packetLoss != 0 +} + func (i *Instance) validateStateForObsy(endpoint string) error { if !i.IsInState(Preparing, Committed) { return fmt.Errorf("setting %s is only allowed in state 'Preparing' or 'Committed'. Current state is '%s'", endpoint, i.state.String()) @@ -531,3 +570,43 @@ func (i *Instance) addOtelCollectorSidecar() error { } return nil } + +func (i *Instance) createNetworkConfigInstance() (*Instance, error) { + networkConfigInstance, err := NewInstance("network-config") + if err != nil { + return nil, fmt.Errorf("error creating network-config instance: %w", err) + } + if err := networkConfigInstance.SetImage("ttl.sh/41838c59-c02e-4cac-9284-e3f47d32391d:latest"); err != nil { + return nil, fmt.Errorf("error setting image for network-config instance: %w", err) + } + if err := networkConfigInstance.Commit(); err != nil { + return nil, fmt.Errorf("error committing network-config instance: %w", err) + } + return networkConfigInstance, nil +} + +func (i *Instance) addNetworkConfigSidecar() error { + networkConfigSidecar, err := i.createNetworkConfigInstance() + if err != nil { + return fmt.Errorf("error creating network config instance '%s': %w", i.k8sName, err) + } + bittwisterCmd := []string{"./bittwister", "start", "-d", "eth0"} + switch { + case i.networkConfig.bandwidth != 0: + networkConfigSidecar.SetCommand(append(bittwisterCmd, "-b", fmt.Sprintf("%d", i.networkConfig.bandwidth))...) + networkConfigSidecar.SetPrivileged(true) + case i.networkConfig.jitter != 0: + networkConfigSidecar.SetCommand(append(bittwisterCmd, "-j", fmt.Sprintf("%d", i.networkConfig.jitter))...) + networkConfigSidecar.AddCapability("NET_ADMIN") + case i.networkConfig.latency != 0: + networkConfigSidecar.SetCommand(append(bittwisterCmd, "-l", fmt.Sprintf("%d", i.networkConfig.latency))...) + networkConfigSidecar.AddCapability("NET_ADMIN") + case i.networkConfig.packetLoss != 0: + networkConfigSidecar.SetCommand(append(bittwisterCmd, "-p", fmt.Sprintf("%d", i.networkConfig.packetLoss))...) + networkConfigSidecar.SetPrivileged(true) + } + if err := i.AddSidecar(networkConfigSidecar); err != nil { + return fmt.Errorf("error adding network config sidecar to instance '%s': %w", i.k8sName, err) + } + return nil +} From 1d6b5b8b6ddcb127032fd4fbee4b70d1fbf432e4 Mon Sep 17 00:00:00 2001 From: Smuu <18609909+Smuu@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:55:57 +0100 Subject: [PATCH 2/8] feat: use official bittwister contaier Signed-off-by: Smuu <18609909+Smuu@users.noreply.github.com> --- pkg/knuu/instance_helper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/knuu/instance_helper.go b/pkg/knuu/instance_helper.go index 6886277..28dd1ba 100644 --- a/pkg/knuu/instance_helper.go +++ b/pkg/knuu/instance_helper.go @@ -576,7 +576,7 @@ func (i *Instance) createNetworkConfigInstance() (*Instance, error) { if err != nil { return nil, fmt.Errorf("error creating network-config instance: %w", err) } - if err := networkConfigInstance.SetImage("ttl.sh/41838c59-c02e-4cac-9284-e3f47d32391d:latest"); err != nil { + if err := networkConfigInstance.SetImage("ghcr.io/celestiaorg/bittwister:b6e321c"); err != nil { return nil, fmt.Errorf("error setting image for network-config instance: %w", err) } if err := networkConfigInstance.Commit(); err != nil { From eb04007917b31189bd716974994f94986f7ef8df Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Wed, 6 Dec 2023 17:46:15 +0100 Subject: [PATCH 3/8] feat: bittwister sdk added --- go.mod | 23 ++++-- go.sum | 58 ++++++++++++---- pkg/knuu/instance.go | 135 +++++++++++++++++++++--------------- pkg/knuu/instance_helper.go | 43 +++++------- 4 files changed, 154 insertions(+), 105 deletions(-) diff --git a/go.mod b/go.mod index e817845..ed6f47e 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,9 @@ module github.com/celestiaorg/knuu -go 1.20 +go 1.21.0 require ( + github.com/celestiaorg/bittwister v0.0.0-20231206153416-6973bcf6b7de github.com/docker/docker v24.0.7+incompatible github.com/google/uuid v1.3.1 github.com/sirupsen/logrus v1.9.3 @@ -14,11 +15,13 @@ require ( require ( github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/cilium/ebpf v0.12.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect @@ -28,6 +31,8 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/gorilla/handlers v1.5.2 // indirect + github.com/gorilla/mux v1.8.1 // indirect github.com/imdario/mergo v0.3.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -42,14 +47,18 @@ require ( github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.17.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.11.0 // indirect + golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.8.0 // indirect + golang.org/x/tools v0.16.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index b40ae8b..a23e944 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,13 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/celestiaorg/bittwister v0.0.0-20231206153416-6973bcf6b7de h1:mKh568+LdPkC9ESxzXaNNAbS4UwhjrEzmSy0zsfj3wQ= +github.com/celestiaorg/bittwister v0.0.0-20231206153416-6973bcf6b7de/go.mod h1:1EF5MfOxVf0WC51Gb7pJ6bcZxnXKNAf9pqWtjgPBAYc= +github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= +github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -16,6 +22,10 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= +github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -26,6 +36,7 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -41,8 +52,13 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -54,6 +70,7 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -74,7 +91,9 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= +github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= @@ -84,6 +103,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -96,43 +116,53 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.11.0 h1:gSmpCfs+R47a4yQPAI4xJ0IPDLTRGXskm6UelqNXpqE= +go.uber.org/zap v1.11.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= +golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -140,8 +170,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/knuu/instance.go b/pkg/knuu/instance.go index ca191e3..5d2243c 100644 --- a/pkg/knuu/instance.go +++ b/pkg/knuu/instance.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/celestiaorg/bittwister/sdk" "github.com/celestiaorg/knuu/pkg/container" "github.com/celestiaorg/knuu/pkg/k8s" "github.com/sirupsen/logrus" @@ -17,6 +18,17 @@ import ( rbacv1 "k8s.io/api/rbac/v1" ) +const ( + // BitTwister default port + btDefaultPort = 9009 + + // BitTwister default image + btDefaultImage = "ghcr.io/celestiaorg/bittwister:b6e321c" + + // Default network interface name inside the pod + btDefaultNetworkInterface = "eth0" +) + // ObsyConfig represents the configuration for the obsy sidecar type ObsyConfig struct { // otelCollectorVersion is the version of the otel collector to use @@ -57,21 +69,6 @@ type SecurityContext struct { capabilitiesAdd []string } -// NetworkConfig represents the configuration for the network -type NetworkConfig struct { - // bandwidth is the bandwidth limit in bps (e.g. 1000 for 1Kbps) - bandwidth int - - // jitter is the network jitter in milliseconds (e.g. 10 for 10ms) - jitter int - - // latency is the network latency in milliseconds (e.g. 100 for 100ms) - latency int - - // packetLoss is the network packet loss rate (e.g. 10 for 10% packet loss) - packetLoss int -} - // Instance represents a instance type Instance struct { name string @@ -102,7 +99,7 @@ type Instance struct { fsGroup int64 obsyConfig *ObsyConfig securityContext *SecurityContext - networkConfig *NetworkConfig + btClient *sdk.Client } // NewInstance creates a new instance of the Instance struct @@ -131,12 +128,7 @@ func NewInstance(name string) (*Instance, error) { privileged: false, capabilitiesAdd: make([]string, 0), } - networkConfig := &NetworkConfig{ - bandwidth: 0, - jitter: 0, - latency: 0, - packetLoss: 0, - } + // Create the instance return &Instance{ name: name, @@ -163,7 +155,6 @@ func NewInstance(name string) (*Instance, error) { sidecars: make([]*Instance, 0), obsyConfig: obsyConfig, securityContext: securityContext, - networkConfig: networkConfig, }, nil } @@ -565,6 +556,15 @@ func (i *Instance) Commit() error { i.state = Committed logrus.Debugf("Set state of instance '%s' to '%s'", i.name, i.state.String()) + ip, err := i.GetIP() + if err != nil { + return fmt.Errorf("error getting IP of instance '%s': %w", i.name, err) + } + logrus.Debugf("IP of instance '%s' is '%s'", i.name, ip) + btAddress := fmt.Sprintf("%s:%d", ip, btDefaultPort) + logrus.Debugf("BitTwister address '%s'", btAddress) + i.btClient = sdk.NewClient(btAddress) + return nil } @@ -881,11 +881,9 @@ func (i *Instance) StartWithoutWait() error { return fmt.Errorf("error adding OpenTelemetry collector sidecar for instance '%s': %w", i.k8sName, err) } } - // check if networking is configured and if so, add the corresponding sidecar - if i.isNetworkConfigSet() { - if err := i.addNetworkConfigSidecar(); err != nil { - return fmt.Errorf("error adding network sidecar for instance '%s': %w", i.k8sName, err) - } + // gholi + if err := i.addNetworkConfigSidecar(); err != nil { + return fmt.Errorf("error adding network sidecar for instance '%s': %w", i.k8sName, err) } if err := i.deployResources(); err != nil { @@ -979,47 +977,58 @@ func (i *Instance) DisableNetwork() error { // bandwidth limit in bps (e.g. 1000 for 1Kbps) // Currently, only one of bandwidth, jitter, latency or packet loss can be set // This function can only be called in the state 'Commited' -func (i *Instance) SetBandwidthLimit(limit int) error { +func (i *Instance) SetBandwidthLimit(limit int64) error { if !i.IsInState(Committed) { return fmt.Errorf("setting bandwidth limit is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) } - if i.isNetworkConfigSet() { - return fmt.Errorf("setting bandwidth limit is not allowed if network config is already set") - } - i.networkConfig.bandwidth = limit - logrus.Debugf("Set bandwidth limit to '%d' in instance '%s'", limit, i.name) - return nil -} -// SetJitter sets the jitter of the instance -// jitter in ms (e.g. 1000 for 1s) -// Currently, only one of bandwidth, jitter, latency or packet loss can be set -// This function can only be called in the state 'Commited' -func (i *Instance) SetJitter(jitter int) error { - if !i.IsInState(Committed) { - return fmt.Errorf("setting jitter is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + // We first need to stop it, otherwise we get an error + if err := i.btClient.BandwidthStop(); err != nil { + if !sdk.IsErrorServiceNotInitialized(err) && !sdk.IsErrorServiceNotReady(err) { + return fmt.Errorf("error stopping bandwidth limit for instance '%s': %w", i.k8sName, err) + } } - if i.isNetworkConfigSet() { - return fmt.Errorf("setting jitter is not allowed if network config is already set") + + err := i.btClient.BandwidthStart(sdk.BandwidthStartRequest{ + NetworkInterfaceName: btDefaultNetworkInterface, + Limit: limit, + }) + + if err != nil { + return fmt.Errorf("error setting bandwidth limit for instance '%s': %w", i.k8sName, err) } - i.networkConfig.jitter = jitter - logrus.Debugf("Set jitter to '%d' in instance '%s'", jitter, i.name) + + logrus.Debugf("Set bandwidth limit to '%d' in instance '%s'", limit, i.name) return nil } // SetLatency sets the latency of the instance // latency in ms (e.g. 1000 for 1s) +// jitter in ms (e.g. 1000 for 1s) // Currently, only one of bandwidth, jitter, latency or packet loss can be set // This function can only be called in the state 'Commited' -func (i *Instance) SetLatency(latency int) error { +func (i *Instance) SetLatencyAndJitter(latency, jitter int64) error { if !i.IsInState(Committed) { - return fmt.Errorf("setting latency is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + return fmt.Errorf("setting latency/jitter is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + } + + // We first need to stop it, otherwise we get an error + if err := i.btClient.LatencyStop(); err != nil { + if !sdk.IsErrorServiceNotInitialized(err) && !sdk.IsErrorServiceNotReady(err) { + return fmt.Errorf("error stopping latency/jitter for instance '%s': %w", i.k8sName, err) + } } - if i.isNetworkConfigSet() { - return fmt.Errorf("setting latency is not allowed if network config is already set") + + err := i.btClient.LatencyStart(sdk.LatencyStartRequest{ + NetworkInterfaceName: btDefaultImage, + Latency: latency, + Jitter: jitter, + }) + if err != nil { + return fmt.Errorf("error setting latency/jitter for instance '%s': %w", i.k8sName, err) } - i.networkConfig.latency = latency - logrus.Debugf("Set latency to '%d' in instance '%s'", latency, i.name) + + logrus.Debugf("Set latency to '%d' and jitter to '%d' in instance '%s'", latency, jitter, i.name) return nil } @@ -1027,14 +1036,26 @@ func (i *Instance) SetLatency(latency int) error { // packet loss in percent (e.g. 10 for 10%) // Currently, only one of bandwidth, jitter, latency or packet loss can be set // This function can only be called in the state 'Commited' -func (i *Instance) SetPacketLoss(packetLoss int) error { +func (i *Instance) SetPacketLoss(packetLoss int32) error { if !i.IsInState(Committed) { return fmt.Errorf("setting packet loss is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) } - if i.isNetworkConfigSet() { - return fmt.Errorf("setting packet loss is not allowed if network config is already set") + + // We first need to stop it, otherwise we get an error + if err := i.btClient.PacketlossStop(); err != nil { + if !sdk.IsErrorServiceNotInitialized(err) && !sdk.IsErrorServiceNotReady(err) { + return fmt.Errorf("error stopping packetLoss for instance '%s': %w", i.k8sName, err) + } } - i.networkConfig.packetLoss = packetLoss + + err := i.btClient.PacketlossStart(sdk.PacketLossStartRequest{ + NetworkInterfaceName: btDefaultNetworkInterface, + PacketLossRate: packetLoss, + }) + if err != nil { + return fmt.Errorf("error setting packet loss for instance '%s': %w", i.k8sName, err) + } + logrus.Debugf("Set packet loss to '%d' in instance '%s'", packetLoss, i.name) return nil } diff --git a/pkg/knuu/instance_helper.go b/pkg/knuu/instance_helper.go index 28dd1ba..0b7f691 100644 --- a/pkg/knuu/instance_helper.go +++ b/pkg/knuu/instance_helper.go @@ -104,9 +104,7 @@ func (i *Instance) patchService() error { // destroyService destroys the service for the instance func (i *Instance) destroyService() error { - k8s.DeleteService(k8s.Namespace(), i.k8sName) - - return nil + return k8s.DeleteService(k8s.Namespace(), i.k8sName) } // deployPod deploys the pod for the instance @@ -323,9 +321,6 @@ func (i *Instance) cloneWithSuffix(suffix string) *Instance { clonedSidecars[i] = sidecar.cloneWithSuffix(suffix) } - // Deep copy of networkConfig to ensure cloned instance has its own copy - clonedNetworkConfig := *i.networkConfig - // Deep copy of securityContext to ensure cloned instance has its own copy clonedSecurityContext := *i.securityContext @@ -356,7 +351,7 @@ func (i *Instance) cloneWithSuffix(suffix string) *Instance { sidecars: clonedSidecars, obsyConfig: i.obsyConfig, securityContext: &clonedSecurityContext, - networkConfig: &clonedNetworkConfig, + btClient: nil, // Set it to nil as it points to the current instance, will create a new one on commit } } @@ -548,11 +543,6 @@ func (i *Instance) isObservabilityEnabled() bool { return i.obsyConfig.otlpPort != 0 || i.obsyConfig.prometheusPort != 0 || i.obsyConfig.jaegerGrpcPort != 0 || i.obsyConfig.jaegerThriftCompactPort != 0 || i.obsyConfig.jaegerThriftHttpPort != 0 } -// isNetworkConfigSet returns true if any network config value is set -func (i *Instance) isNetworkConfigSet() bool { - return i.networkConfig.bandwidth != 0 || i.networkConfig.jitter != 0 || i.networkConfig.latency != 0 || i.networkConfig.packetLoss != 0 -} - func (i *Instance) validateStateForObsy(endpoint string) error { if !i.IsInState(Preparing, Committed) { return fmt.Errorf("setting %s is only allowed in state 'Preparing' or 'Committed'. Current state is '%s'", endpoint, i.state.String()) @@ -576,9 +566,14 @@ func (i *Instance) createNetworkConfigInstance() (*Instance, error) { if err != nil { return nil, fmt.Errorf("error creating network-config instance: %w", err) } - if err := networkConfigInstance.SetImage("ghcr.io/celestiaorg/bittwister:b6e321c"); err != nil { + if err := networkConfigInstance.SetImage(btDefaultImage); err != nil { return nil, fmt.Errorf("error setting image for network-config instance: %w", err) } + + if err := networkConfigInstance.SetEnvironmentVariable("SERVE_ADDR", fmt.Sprintf("0.0.0.0:%d", btDefaultPort)); err != nil { + return nil, fmt.Errorf("error setting environment variable for network-config instance: %w", err) + } + if err := networkConfigInstance.Commit(); err != nil { return nil, fmt.Errorf("error committing network-config instance: %w", err) } @@ -590,21 +585,15 @@ func (i *Instance) addNetworkConfigSidecar() error { if err != nil { return fmt.Errorf("error creating network config instance '%s': %w", i.k8sName, err) } - bittwisterCmd := []string{"./bittwister", "start", "-d", "eth0"} - switch { - case i.networkConfig.bandwidth != 0: - networkConfigSidecar.SetCommand(append(bittwisterCmd, "-b", fmt.Sprintf("%d", i.networkConfig.bandwidth))...) - networkConfigSidecar.SetPrivileged(true) - case i.networkConfig.jitter != 0: - networkConfigSidecar.SetCommand(append(bittwisterCmd, "-j", fmt.Sprintf("%d", i.networkConfig.jitter))...) - networkConfigSidecar.AddCapability("NET_ADMIN") - case i.networkConfig.latency != 0: - networkConfigSidecar.SetCommand(append(bittwisterCmd, "-l", fmt.Sprintf("%d", i.networkConfig.latency))...) - networkConfigSidecar.AddCapability("NET_ADMIN") - case i.networkConfig.packetLoss != 0: - networkConfigSidecar.SetCommand(append(bittwisterCmd, "-p", fmt.Sprintf("%d", i.networkConfig.packetLoss))...) - networkConfigSidecar.SetPrivileged(true) + + if err := networkConfigSidecar.SetPrivileged(true); err != nil { + return fmt.Errorf("error setting privileged for network config instance '%s': %w", i.k8sName, err) + } + + if err := networkConfigSidecar.AddCapability("NET_ADMIN"); err != nil { + return fmt.Errorf("error adding capability for network config instance '%s': %w", i.k8sName, err) } + if err := i.AddSidecar(networkConfigSidecar); err != nil { return fmt.Errorf("error adding network config sidecar to instance '%s': %w", i.k8sName, err) } From b6f4c88357d64a0dcbe60a5f34f869c302852a90 Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Wed, 6 Dec 2023 19:03:34 +0100 Subject: [PATCH 4/8] fix: bittwister version --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ed6f47e..bd0b563 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/celestiaorg/knuu go 1.21.0 require ( - github.com/celestiaorg/bittwister v0.0.0-20231206153416-6973bcf6b7de + github.com/celestiaorg/bittwister v0.0.0-20231206180026-b04bbe8f7ba8 github.com/docker/docker v24.0.7+incompatible github.com/google/uuid v1.3.1 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index a23e944..3b2310c 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/celestiaorg/bittwister v0.0.0-20231206153416-6973bcf6b7de h1:mKh568+LdPkC9ESxzXaNNAbS4UwhjrEzmSy0zsfj3wQ= -github.com/celestiaorg/bittwister v0.0.0-20231206153416-6973bcf6b7de/go.mod h1:1EF5MfOxVf0WC51Gb7pJ6bcZxnXKNAf9pqWtjgPBAYc= +github.com/celestiaorg/bittwister v0.0.0-20231206180026-b04bbe8f7ba8 h1:rIHmhLb/tUBhYFnYmCPRnrYNKPTyxoPCyIGJwT+8fbQ= +github.com/celestiaorg/bittwister v0.0.0-20231206180026-b04bbe8f7ba8/go.mod h1:1EF5MfOxVf0WC51Gb7pJ6bcZxnXKNAf9pqWtjgPBAYc= github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= From 5afaa99b6bf3ef5c34e77bc57b6d1978fd91a3cf Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Thu, 7 Dec 2023 11:30:00 +0100 Subject: [PATCH 5/8] chore: update bittwister version --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index bd0b563..f774110 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/celestiaorg/knuu go 1.21.0 require ( - github.com/celestiaorg/bittwister v0.0.0-20231206180026-b04bbe8f7ba8 + github.com/celestiaorg/bittwister v0.0.0-20231207100307-b76451880378 github.com/docker/docker v24.0.7+incompatible github.com/google/uuid v1.3.1 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index 3b2310c..09325ac 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/celestiaorg/bittwister v0.0.0-20231206180026-b04bbe8f7ba8 h1:rIHmhLb/tUBhYFnYmCPRnrYNKPTyxoPCyIGJwT+8fbQ= -github.com/celestiaorg/bittwister v0.0.0-20231206180026-b04bbe8f7ba8/go.mod h1:1EF5MfOxVf0WC51Gb7pJ6bcZxnXKNAf9pqWtjgPBAYc= +github.com/celestiaorg/bittwister v0.0.0-20231207100307-b76451880378 h1:4Z3NTtuKQwDPPFh76bhHaBq2t8vzzBSY86XPSCv+TW4= +github.com/celestiaorg/bittwister v0.0.0-20231207100307-b76451880378/go.mod h1:1EF5MfOxVf0WC51Gb7pJ6bcZxnXKNAf9pqWtjgPBAYc= github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= From 015e22e5bdce53ba5d9c90f8623ff9d271a8da69 Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Wed, 13 Dec 2023 20:00:41 +0100 Subject: [PATCH 6/8] feat: bittwister integration --- pkg/k8s/k8s_pod.go | 7 +- pkg/k8s/utils.go | 4 + pkg/knuu/bittwister.go | 80 ++++++++++++++++++ pkg/knuu/executor.go | 9 +- pkg/knuu/instance.go | 163 +++++++++++++++++++++--------------- pkg/knuu/instance_helper.go | 44 +++++++--- 6 files changed, 221 insertions(+), 86 deletions(-) create mode 100644 pkg/knuu/bittwister.go diff --git a/pkg/k8s/k8s_pod.go b/pkg/k8s/k8s_pod.go index 9471f0a..62790dd 100644 --- a/pkg/k8s/k8s_pod.go +++ b/pkg/k8s/k8s_pod.go @@ -169,8 +169,9 @@ func IsPodRunning(namespace, name string) (bool, error) { return true, nil } -// RunCommandInPod runs a command in a container within a pod. +// RunCommandInPod runs a command in a container within a pod with a context. func RunCommandInPod( + ctx context.Context, namespace, podName, containerName string, @@ -210,9 +211,6 @@ func RunCommandInPod( return "", fmt.Errorf("failed to create Executor: %v", err) } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - // Execute the command and capture the output and error streams var stdout, stderr bytes.Buffer err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{ @@ -220,6 +218,7 @@ func RunCommandInPod( Stderr: &stderr, Tty: false, }) + if err != nil { return "", fmt.Errorf("failed to execute command: %v", err) } diff --git a/pkg/k8s/utils.go b/pkg/k8s/utils.go index 4c3d3e6..82fb478 100644 --- a/pkg/k8s/utils.go +++ b/pkg/k8s/utils.go @@ -10,6 +10,10 @@ var namespace = "" // timeout is the timeout for Kubernetes operations const timeout = 20 * time.Second +func Timeout() time.Duration { + return timeout +} + // Namespace returns the current namespace in use. func Namespace() string { return namespace diff --git a/pkg/knuu/bittwister.go b/pkg/knuu/bittwister.go new file mode 100644 index 0000000..1f004dc --- /dev/null +++ b/pkg/knuu/bittwister.go @@ -0,0 +1,80 @@ +package knuu + +import ( + "fmt" + + "github.com/celestiaorg/bittwister/sdk" + "github.com/sirupsen/logrus" +) + +const ( + btDefaultPort = 9009 + btDefaultImage = "ghcr.io/celestiaorg/bittwister:f5f94e6" + btDefaultNetworkInterface = "eth0" +) + +type btConfig struct { + port int + image string + networkInterface string + client *sdk.Client + enabled bool // if true, BitTwister is enabled and will be deployed as a sidecar +} + +func getBitTwisterDefaultConfig() *btConfig { + return &btConfig{ + port: btDefaultPort, + image: btDefaultImage, + networkInterface: btDefaultNetworkInterface, + } +} + +func (c *btConfig) SetPort(port int) { + c.port = port +} + +func (c *btConfig) SetImage(image string) { + c.image = image +} + +func (c *btConfig) SetNetworkInterface(networkInterface string) { + c.networkInterface = networkInterface +} + +func (c *btConfig) SetClient(client *sdk.Client) { + c.client = client +} + +func (c *btConfig) SetNewClientByIPAddr(ip string) { + btAddress := fmt.Sprintf("%s:%d", ip, c.port) + c.client = sdk.NewClient(btAddress) + logrus.Debugf("BitTwister address '%s'", btAddress) +} + +func (c *btConfig) Port() int { + return c.port +} + +func (c *btConfig) Image() string { + return c.image +} + +func (c *btConfig) NetworkInterface() string { + return c.networkInterface +} + +func (c *btConfig) Client() *sdk.Client { + return c.client +} + +func (c *btConfig) Enabled() bool { + return c.enabled +} + +func (c *btConfig) enable() { + c.enabled = true +} + +func (c *btConfig) disable() { + c.enabled = false +} diff --git a/pkg/knuu/executor.go b/pkg/knuu/executor.go index a4ed417..cda7539 100644 --- a/pkg/knuu/executor.go +++ b/pkg/knuu/executor.go @@ -1,6 +1,9 @@ package knuu -import "fmt" +import ( + "context" + "fmt" +) type Executor struct { instances *Instance @@ -49,6 +52,10 @@ func (e *Executor) ExecuteCommand(command ...string) (string, error) { return e.instances.ExecuteCommand(command...) } +func (e *Executor) ExecuteCommandWithContext(ctx context.Context, command ...string) (string, error) { + return e.instances.ExecuteCommandWithContext(ctx, command...) +} + func (e *Executor) Destroy() error { return e.instances.Destroy() } diff --git a/pkg/knuu/instance.go b/pkg/knuu/instance.go index 5d2243c..8e5dd54 100644 --- a/pkg/knuu/instance.go +++ b/pkg/knuu/instance.go @@ -1,6 +1,7 @@ package knuu import ( + "context" "fmt" "io" "os" @@ -18,17 +19,6 @@ import ( rbacv1 "k8s.io/api/rbac/v1" ) -const ( - // BitTwister default port - btDefaultPort = 9009 - - // BitTwister default image - btDefaultImage = "ghcr.io/celestiaorg/bittwister:b6e321c" - - // Default network interface name inside the pod - btDefaultNetworkInterface = "eth0" -) - // ObsyConfig represents the configuration for the obsy sidecar type ObsyConfig struct { // otelCollectorVersion is the version of the otel collector to use @@ -99,7 +89,7 @@ type Instance struct { fsGroup int64 obsyConfig *ObsyConfig securityContext *SecurityContext - btClient *sdk.Client + BitTwister *btConfig } // NewInstance creates a new instance of the Instance struct @@ -155,9 +145,26 @@ func NewInstance(name string) (*Instance, error) { sidecars: make([]*Instance, 0), obsyConfig: obsyConfig, securityContext: securityContext, + BitTwister: getBitTwisterDefaultConfig(), }, nil } +func (i *Instance) EnableBitTwister() error { + if i.IsInState(Started) { + return fmt.Errorf("enabling BitTwister is not allowed in state 'Started'") + } + i.BitTwister.enable() + return nil +} + +func (i *Instance) DisableBitTwister() error { + // if !i.IsInState(Preparing) { + // return fmt.Errorf("disabling BitTwister is only allowed in state 'Preparing'. Current state is '%s'", i.state.String()) + // } + i.BitTwister.disable() + return nil +} + // SetImage sets the image of the instance. // When calling in state 'Started', make sure to call AddVolume() before. // It is only allowed in the 'None' and 'Started' states. @@ -313,43 +320,53 @@ func (i *Instance) AddPortUDP(port int) error { // ExecuteCommand executes the given command in the instance // This function can only be called in the states 'Preparing' and 'Started' func (i *Instance) ExecuteCommand(command ...string) (string, error) { + ctx, cancel := context.WithTimeout(context.Background(), k8s.Timeout()) + defer cancel() + + return i.ExecuteCommandWithContext(ctx, command...) +} + +// ExecuteCommandWithContext executes the given command in the instance +// This function can only be called in the states 'Preparing' and 'Started' +// The context can be used to cancel the command and it is only possible in start state +func (i *Instance) ExecuteCommandWithContext(ctx context.Context, command ...string) (string, error) { if !i.IsInState(Preparing, Started) { return "", fmt.Errorf("executing command is only allowed in state 'Preparing' or 'Started'. Current state is '%s'", i.state.String()) } + if i.IsInState(Preparing) { output, err := i.builderFactory.ExecuteCmdInBuilder(command) if err != nil { return "", fmt.Errorf("error executing command '%s' in instance '%s': %v", command, i.name, err) } return output, nil - } else if i.IsInState(Started) { - var instanceName string - var errMsg error - containerName := i.k8sName + } - if i.isSidecar { - instanceName = i.parentInstance.k8sName - errMsg = fmt.Errorf("error executing command '%s' in sidecar '%s' of instance '%s'", command, i.k8sName, i.parentInstance.k8sName) - } else { - instanceName = i.k8sName - errMsg = fmt.Errorf("error executing command '%s' in instance '%s'", command, i.k8sName) - } + var ( + instanceName string + errMsg error + containerName = i.k8sName + ) - pod, err := k8s.GetFirstPodFromStatefulSet(k8s.Namespace(), instanceName) - if err != nil { - return "", fmt.Errorf("error getting pod from statefulset '%s': %v", i.k8sName, err) - } - commandWithShell := []string{"/bin/sh", "-c", strings.Join(command, " ")} - output, err := k8s.RunCommandInPod(k8s.Namespace(), pod.Name, containerName, commandWithShell) - if err != nil { - return "", fmt.Errorf("%v: %v", errMsg, err) - } - return output, nil + if i.isSidecar { + instanceName = i.parentInstance.k8sName + errMsg = fmt.Errorf("error executing command '%s' in sidecar '%s' of instance '%s'", command, i.k8sName, i.parentInstance.k8sName) } else { - return "", fmt.Errorf("") + instanceName = i.k8sName + errMsg = fmt.Errorf("error executing command '%s' in instance '%s'", command, i.k8sName) + } + + pod, err := k8s.GetFirstPodFromStatefulSet(k8s.Namespace(), instanceName) + if err != nil { + return "", fmt.Errorf("error getting pod from statefulset '%s': %v", i.k8sName, err) } - return "", nil + commandWithShell := []string{"/bin/sh", "-c", strings.Join(command, " ")} + output, err := k8s.RunCommandInPod(ctx, k8s.Namespace(), pod.Name, containerName, commandWithShell) + if err != nil { + return "", fmt.Errorf("%v: %v", errMsg, err) + } + return output, nil } // checkStateForAddingFile checks if the current state allows adding a file @@ -556,15 +573,6 @@ func (i *Instance) Commit() error { i.state = Committed logrus.Debugf("Set state of instance '%s' to '%s'", i.name, i.state.String()) - ip, err := i.GetIP() - if err != nil { - return fmt.Errorf("error getting IP of instance '%s': %w", i.name, err) - } - logrus.Debugf("IP of instance '%s' is '%s'", i.name, ip) - btAddress := fmt.Sprintf("%s:%d", ip, btDefaultPort) - logrus.Debugf("BitTwister address '%s'", btAddress) - i.btClient = sdk.NewClient(btAddress) - return nil } @@ -874,6 +882,7 @@ func (i *Instance) StartWithoutWait() error { if i.isSidecar { return fmt.Errorf("starting a sidecar is not allowed") } + if i.state == Committed { // deploy otel collector if observability is enabled if i.isObservabilityEnabled() { @@ -881,9 +890,11 @@ func (i *Instance) StartWithoutWait() error { return fmt.Errorf("error adding OpenTelemetry collector sidecar for instance '%s': %w", i.k8sName, err) } } - // gholi - if err := i.addNetworkConfigSidecar(); err != nil { - return fmt.Errorf("error adding network sidecar for instance '%s': %w", i.k8sName, err) + + if i.BitTwister.Enabled() || i.isObservabilityEnabled() { + if err := i.addNetworkConfigSidecar(); err != nil { + return fmt.Errorf("error adding network sidecar for instance '%s': %w", i.k8sName, err) + } } if err := i.deployResources(); err != nil { @@ -894,8 +905,8 @@ func (i *Instance) StartWithoutWait() error { }); err != nil { return fmt.Errorf("error deploying resources for sidecars of instance '%s': %w", i.k8sName, err) } - } + err := i.deployPod() if err != nil { return fmt.Errorf("error deploying pod for instance '%s': %w", i.k8sName, err) @@ -978,22 +989,26 @@ func (i *Instance) DisableNetwork() error { // Currently, only one of bandwidth, jitter, latency or packet loss can be set // This function can only be called in the state 'Commited' func (i *Instance) SetBandwidthLimit(limit int64) error { - if !i.IsInState(Committed) { - return fmt.Errorf("setting bandwidth limit is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + if !i.IsInState(Started) { + return fmt.Errorf("setting bandwidth limit is only allowed in state 'Started'. Current state is '%s'", i.state.String()) + } + if !i.BitTwister.Enabled() { + return fmt.Errorf("setting bandwidth limit is only allowed if BitTwister is enabled") } // We first need to stop it, otherwise we get an error - if err := i.btClient.BandwidthStop(); err != nil { - if !sdk.IsErrorServiceNotInitialized(err) && !sdk.IsErrorServiceNotReady(err) { + if err := i.BitTwister.Client().BandwidthStop(); err != nil { + if !sdk.IsErrorServiceNotInitialized(err) && + !sdk.IsErrorServiceNotReady(err) && + !sdk.IsErrorServiceNotStarted(err) { return fmt.Errorf("error stopping bandwidth limit for instance '%s': %w", i.k8sName, err) } } - err := i.btClient.BandwidthStart(sdk.BandwidthStartRequest{ - NetworkInterfaceName: btDefaultNetworkInterface, + err := i.BitTwister.Client().BandwidthStart(sdk.BandwidthStartRequest{ + NetworkInterfaceName: i.BitTwister.NetworkInterface(), Limit: limit, }) - if err != nil { return fmt.Errorf("error setting bandwidth limit for instance '%s': %w", i.k8sName, err) } @@ -1008,19 +1023,24 @@ func (i *Instance) SetBandwidthLimit(limit int64) error { // Currently, only one of bandwidth, jitter, latency or packet loss can be set // This function can only be called in the state 'Commited' func (i *Instance) SetLatencyAndJitter(latency, jitter int64) error { - if !i.IsInState(Committed) { - return fmt.Errorf("setting latency/jitter is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + if !i.IsInState(Started) { + return fmt.Errorf("setting latency/jitter is only allowed in state 'Started'. Current state is '%s'", i.state.String()) + } + if !i.BitTwister.Enabled() { + return fmt.Errorf("setting latency/jitter is only allowed if BitTwister is enabled") } // We first need to stop it, otherwise we get an error - if err := i.btClient.LatencyStop(); err != nil { - if !sdk.IsErrorServiceNotInitialized(err) && !sdk.IsErrorServiceNotReady(err) { + if err := i.BitTwister.Client().LatencyStop(); err != nil { + if !sdk.IsErrorServiceNotInitialized(err) && + !sdk.IsErrorServiceNotReady(err) && + !sdk.IsErrorServiceNotStarted(err) { return fmt.Errorf("error stopping latency/jitter for instance '%s': %w", i.k8sName, err) } } - err := i.btClient.LatencyStart(sdk.LatencyStartRequest{ - NetworkInterfaceName: btDefaultImage, + err := i.BitTwister.Client().LatencyStart(sdk.LatencyStartRequest{ + NetworkInterfaceName: i.BitTwister.NetworkInterface(), Latency: latency, Jitter: jitter, }) @@ -1037,23 +1057,28 @@ func (i *Instance) SetLatencyAndJitter(latency, jitter int64) error { // Currently, only one of bandwidth, jitter, latency or packet loss can be set // This function can only be called in the state 'Commited' func (i *Instance) SetPacketLoss(packetLoss int32) error { - if !i.IsInState(Committed) { - return fmt.Errorf("setting packet loss is only allowed in state 'Committed'. Current state is '%s'", i.state.String()) + if !i.IsInState(Started) { + return fmt.Errorf("setting packetloss is only allowed in state 'Started'. Current state is '%s'", i.state.String()) + } + if !i.BitTwister.Enabled() { + return fmt.Errorf("setting packetloss is only allowed if BitTwister is enabled") } // We first need to stop it, otherwise we get an error - if err := i.btClient.PacketlossStop(); err != nil { - if !sdk.IsErrorServiceNotInitialized(err) && !sdk.IsErrorServiceNotReady(err) { - return fmt.Errorf("error stopping packetLoss for instance '%s': %w", i.k8sName, err) + if err := i.BitTwister.Client().PacketlossStop(); err != nil { + if !sdk.IsErrorServiceNotInitialized(err) && + !sdk.IsErrorServiceNotReady(err) && + !sdk.IsErrorServiceNotStarted(err) { + return fmt.Errorf("error stopping packetloss for instance '%s': %w", i.k8sName, err) } } - err := i.btClient.PacketlossStart(sdk.PacketLossStartRequest{ - NetworkInterfaceName: btDefaultNetworkInterface, + err := i.BitTwister.Client().PacketlossStart(sdk.PacketLossStartRequest{ + NetworkInterfaceName: i.BitTwister.NetworkInterface(), PacketLossRate: packetLoss, }) if err != nil { - return fmt.Errorf("error setting packet loss for instance '%s': %w", i.k8sName, err) + return fmt.Errorf("error setting packetloss for instance '%s': %w", i.k8sName, err) } logrus.Debugf("Set packet loss to '%d' in instance '%s'", packetLoss, i.name) diff --git a/pkg/knuu/instance_helper.go b/pkg/knuu/instance_helper.go index 0b7f691..8002677 100644 --- a/pkg/knuu/instance_helper.go +++ b/pkg/knuu/instance_helper.go @@ -315,7 +315,6 @@ func (i *Instance) destroyResources() error { // cloneWithSuffix clones the instance with a suffix func (i *Instance) cloneWithSuffix(suffix string) *Instance { - clonedSidecars := make([]*Instance, len(i.sidecars)) for i, sidecar := range i.sidecars { clonedSidecars[i] = sidecar.cloneWithSuffix(suffix) @@ -324,6 +323,9 @@ func (i *Instance) cloneWithSuffix(suffix string) *Instance { // Deep copy of securityContext to ensure cloned instance has its own copy clonedSecurityContext := *i.securityContext + clonedBitTwister := *i.BitTwister + clonedBitTwister.SetClient(nil) // reset client to avoid reusing the same client + return &Instance{ name: i.name + suffix, k8sName: i.k8sName + suffix, @@ -351,7 +353,7 @@ func (i *Instance) cloneWithSuffix(suffix string) *Instance { sidecars: clonedSidecars, obsyConfig: i.obsyConfig, securityContext: &clonedSecurityContext, - btClient: nil, // Set it to nil as it points to the current instance, will create a new one on commit + BitTwister: &clonedBitTwister, } } @@ -566,17 +568,33 @@ func (i *Instance) createNetworkConfigInstance() (*Instance, error) { if err != nil { return nil, fmt.Errorf("error creating network-config instance: %w", err) } - if err := networkConfigInstance.SetImage(btDefaultImage); err != nil { - return nil, fmt.Errorf("error setting image for network-config instance: %w", err) - } - if err := networkConfigInstance.SetEnvironmentVariable("SERVE_ADDR", fmt.Sprintf("0.0.0.0:%d", btDefaultPort)); err != nil { - return nil, fmt.Errorf("error setting environment variable for network-config instance: %w", err) + if i.BitTwister.Enabled() { + if err := networkConfigInstance.SetImage(i.BitTwister.Image()); err != nil { + return nil, fmt.Errorf("error setting image for network-config instance: %w", err) + } + + if err := networkConfigInstance.SetEnvironmentVariable("SERVE_ADDR", fmt.Sprintf("0.0.0.0:%d", i.BitTwister.Port())); err != nil { + return nil, fmt.Errorf("error setting environment variable for network-config instance: %w", err) + } + + // We need to add the port here so the instance will get an IP + if err := i.AddPortTCP(i.BitTwister.Port()); err != nil { + return nil, fmt.Errorf("error adding BitTwister port: %w", err) + } + ip, err := i.GetIP() + if err != nil { + return nil, fmt.Errorf("error getting IP of instance '%s': %w", i.name, err) + } + logrus.Debugf("IP of instance '%s' is '%s'", i.name, ip) + + i.BitTwister.SetNewClientByIPAddr("http://" + ip) } if err := networkConfigInstance.Commit(); err != nil { return nil, fmt.Errorf("error committing network-config instance: %w", err) } + return networkConfigInstance, nil } @@ -586,12 +604,14 @@ func (i *Instance) addNetworkConfigSidecar() error { return fmt.Errorf("error creating network config instance '%s': %w", i.k8sName, err) } - if err := networkConfigSidecar.SetPrivileged(true); err != nil { - return fmt.Errorf("error setting privileged for network config instance '%s': %w", i.k8sName, err) - } + if i.BitTwister.Enabled() { + if err := networkConfigSidecar.SetPrivileged(true); err != nil { + return fmt.Errorf("error setting privileged for network config instance '%s': %w", i.k8sName, err) + } - if err := networkConfigSidecar.AddCapability("NET_ADMIN"); err != nil { - return fmt.Errorf("error adding capability for network config instance '%s': %w", i.k8sName, err) + if err := networkConfigSidecar.AddCapability("NET_ADMIN"); err != nil { + return fmt.Errorf("error adding capability for network config instance '%s': %w", i.k8sName, err) + } } if err := i.AddSidecar(networkConfigSidecar); err != nil { From 4f9217dc84e2393367c6b830c372ac3fc5c8a18a Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Fri, 15 Dec 2023 12:30:36 +0100 Subject: [PATCH 7/8] chore: applied requested fixes --- pkg/knuu/instance.go | 4 +-- pkg/knuu/instance_helper.go | 66 +++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/pkg/knuu/instance.go b/pkg/knuu/instance.go index 8e5dd54..04bbebd 100644 --- a/pkg/knuu/instance.go +++ b/pkg/knuu/instance.go @@ -891,8 +891,8 @@ func (i *Instance) StartWithoutWait() error { } } - if i.BitTwister.Enabled() || i.isObservabilityEnabled() { - if err := i.addNetworkConfigSidecar(); err != nil { + if i.BitTwister.Enabled() { + if err := i.addBitTwisterSidecar(); err != nil { return fmt.Errorf("error adding network sidecar for instance '%s': %w", i.k8sName, err) } } diff --git a/pkg/knuu/instance_helper.go b/pkg/knuu/instance_helper.go index 8002677..912f4b1 100644 --- a/pkg/knuu/instance_helper.go +++ b/pkg/knuu/instance_helper.go @@ -563,59 +563,55 @@ func (i *Instance) addOtelCollectorSidecar() error { return nil } -func (i *Instance) createNetworkConfigInstance() (*Instance, error) { - networkConfigInstance, err := NewInstance("network-config") +func (i *Instance) createBitTwisterInstance() (*Instance, error) { + bt, err := NewInstance("bit-twister") if err != nil { - return nil, fmt.Errorf("error creating network-config instance: %w", err) + return nil, fmt.Errorf("error creating bit-twister instance: %w", err) } - if i.BitTwister.Enabled() { - if err := networkConfigInstance.SetImage(i.BitTwister.Image()); err != nil { - return nil, fmt.Errorf("error setting image for network-config instance: %w", err) - } - - if err := networkConfigInstance.SetEnvironmentVariable("SERVE_ADDR", fmt.Sprintf("0.0.0.0:%d", i.BitTwister.Port())); err != nil { - return nil, fmt.Errorf("error setting environment variable for network-config instance: %w", err) - } + if err := bt.SetImage(i.BitTwister.Image()); err != nil { + return nil, fmt.Errorf("error setting image for bit-twister instance: %w", err) + } - // We need to add the port here so the instance will get an IP - if err := i.AddPortTCP(i.BitTwister.Port()); err != nil { - return nil, fmt.Errorf("error adding BitTwister port: %w", err) - } - ip, err := i.GetIP() - if err != nil { - return nil, fmt.Errorf("error getting IP of instance '%s': %w", i.name, err) - } - logrus.Debugf("IP of instance '%s' is '%s'", i.name, ip) + if err := bt.SetEnvironmentVariable("SERVE_ADDR", fmt.Sprintf("0.0.0.0:%d", i.BitTwister.Port())); err != nil { + return nil, fmt.Errorf("error setting environment variable for bit-twister instance: %w", err) + } - i.BitTwister.SetNewClientByIPAddr("http://" + ip) + // We need to add the port here so the instance will get an IP + if err := i.AddPortTCP(i.BitTwister.Port()); err != nil { + return nil, fmt.Errorf("error adding BitTwister port: %w", err) + } + ip, err := i.GetIP() + if err != nil { + return nil, fmt.Errorf("error getting IP of instance '%s': %w", i.name, err) } + logrus.Debugf("IP of instance '%s' is '%s'", i.name, ip) + + i.BitTwister.SetNewClientByIPAddr("http://" + ip) - if err := networkConfigInstance.Commit(); err != nil { - return nil, fmt.Errorf("error committing network-config instance: %w", err) + if err := bt.Commit(); err != nil { + return nil, fmt.Errorf("error committing bit-twister instance: %w", err) } - return networkConfigInstance, nil + return bt, nil } -func (i *Instance) addNetworkConfigSidecar() error { - networkConfigSidecar, err := i.createNetworkConfigInstance() +func (i *Instance) addBitTwisterSidecar() error { + networkConfigSidecar, err := i.createBitTwisterInstance() if err != nil { - return fmt.Errorf("error creating network config instance '%s': %w", i.k8sName, err) + return fmt.Errorf("error creating bit-twister instance '%s': %w", i.k8sName, err) } - if i.BitTwister.Enabled() { - if err := networkConfigSidecar.SetPrivileged(true); err != nil { - return fmt.Errorf("error setting privileged for network config instance '%s': %w", i.k8sName, err) - } + if err := networkConfigSidecar.SetPrivileged(true); err != nil { + return fmt.Errorf("error setting privileged for bit-twister instance '%s': %w", i.k8sName, err) + } - if err := networkConfigSidecar.AddCapability("NET_ADMIN"); err != nil { - return fmt.Errorf("error adding capability for network config instance '%s': %w", i.k8sName, err) - } + if err := networkConfigSidecar.AddCapability("NET_ADMIN"); err != nil { + return fmt.Errorf("error adding capability for bit-twister instance '%s': %w", i.k8sName, err) } if err := i.AddSidecar(networkConfigSidecar); err != nil { - return fmt.Errorf("error adding network config sidecar to instance '%s': %w", i.k8sName, err) + return fmt.Errorf("error adding bit-twister sidecar to instance '%s': %w", i.k8sName, err) } return nil } From 02ac9ceebee5bde33e0c5669686805a1e2ecaefa Mon Sep 17 00:00:00 2001 From: Mojtaba Date: Fri, 15 Dec 2023 12:59:48 +0100 Subject: [PATCH 8/8] chore: move env var set after commit --- pkg/knuu/instance_helper.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/knuu/instance_helper.go b/pkg/knuu/instance_helper.go index 912f4b1..926cc78 100644 --- a/pkg/knuu/instance_helper.go +++ b/pkg/knuu/instance_helper.go @@ -573,10 +573,6 @@ func (i *Instance) createBitTwisterInstance() (*Instance, error) { return nil, fmt.Errorf("error setting image for bit-twister instance: %w", err) } - if err := bt.SetEnvironmentVariable("SERVE_ADDR", fmt.Sprintf("0.0.0.0:%d", i.BitTwister.Port())); err != nil { - return nil, fmt.Errorf("error setting environment variable for bit-twister instance: %w", err) - } - // We need to add the port here so the instance will get an IP if err := i.AddPortTCP(i.BitTwister.Port()); err != nil { return nil, fmt.Errorf("error adding BitTwister port: %w", err) @@ -593,6 +589,10 @@ func (i *Instance) createBitTwisterInstance() (*Instance, error) { return nil, fmt.Errorf("error committing bit-twister instance: %w", err) } + if err := bt.SetEnvironmentVariable("SERVE_ADDR", fmt.Sprintf("0.0.0.0:%d", i.BitTwister.Port())); err != nil { + return nil, fmt.Errorf("error setting environment variable for bit-twister instance: %w", err) + } + return bt, nil }