Repository: skupperproject/skupper
Pull request #1127 (2023-05-26 18:29:40)

support for dataConnectionCount tuning option in router
This requires an updated router that supports the option to be usable.


Patch:
diff --git a/api/types/client.go b/api/types/client.go
index 18c03838..3b31aea3 100644
--- a/api/types/client.go
+++ b/api/types/client.go
@@ -58,14 +58,15 @@ type Tuning struct {
 
 type RouterOptions struct {
 	Tuning
-	Logging            []RouterLogConfig
-	DebugMode          string
-	MaxFrameSize       int
-	MaxSessionFrames   int
-	IngressHost        string
-	ServiceAnnotations map[string]string
-	LoadBalancerIp     string
-	DisableMutualTLS   bool
+	Logging             []RouterLogConfig
+	DebugMode           string
+	MaxFrameSize        int
+	MaxSessionFrames    int
+	DataConnectionCount string
+	IngressHost         string
+	ServiceAnnotations  map[string]string
+	LoadBalancerIp      string
+	DisableMutualTLS    bool
 }
 
 type ControllerOptions struct {
diff --git a/client/site_config_create.go b/client/site_config_create.go
index 2f69f9f4..1cca4fe1 100644
--- a/client/site_config_create.go
+++ b/client/site_config_create.go
@@ -55,22 +55,23 @@ const (
 	SiteConfigPrometheusServerMemoryLimitKey    string = "prometheus-server-memory-limit"
 
 	// router options
-	SiteConfigRouterConsoleKey            string = "router-console"
-	SiteConfigRouterLoggingKey            string = "router-logging"
-	SiteConfigRouterDebugModeKey          string = "router-debug-mode"
-	SiteConfigRouterCpuKey                string = "router-cpu"
-	SiteConfigRouterMemoryKey             string = "router-memory"
-	SiteConfigRouterCpuLimitKey           string = "router-cpu-limit"
-	SiteConfigRouterMemoryLimitKey        string = "router-memory-limit"
-	SiteConfigRouterAffinityKey           string = "router-pod-affinity"
-	SiteConfigRouterAntiAffinityKey       string = "router-pod-antiaffinity"
-	SiteConfigRouterNodeSelectorKey       string = "router-node-selector"
-	SiteConfigRouterMaxFrameSizeKey       string = "xp-router-max-frame-size"
-	SiteConfigRouterMaxSessionFramesKey   string = "xp-router-max-session-frames"
-	SiteConfigRouterIngressHostKey        string = "router-ingress-host"
-	SiteConfigRouterServiceAnnotationsKey string = "router-service-annotations"
-	SiteConfigRouterLoadBalancerIp        string = "router-load-balancer-ip"
-	SiteConfigRouterDisableMutualTLS      string = "router-disable-mutual-tls"
+	SiteConfigRouterConsoleKey             string = "router-console"
+	SiteConfigRouterLoggingKey             string = "router-logging"
+	SiteConfigRouterDebugModeKey           string = "router-debug-mode"
+	SiteConfigRouterCpuKey                 string = "router-cpu"
+	SiteConfigRouterMemoryKey              string = "router-memory"
+	SiteConfigRouterCpuLimitKey            string = "router-cpu-limit"
+	SiteConfigRouterMemoryLimitKey         string = "router-memory-limit"
+	SiteConfigRouterAffinityKey            string = "router-pod-affinity"
+	SiteConfigRouterAntiAffinityKey        string = "router-pod-antiaffinity"
+	SiteConfigRouterNodeSelectorKey        string = "router-node-selector"
+	SiteConfigRouterMaxFrameSizeKey        string = "xp-router-max-frame-size"
+	SiteConfigRouterMaxSessionFramesKey    string = "xp-router-max-session-frames"
+	SiteConfigRouterDataConnectionCountKey string = "router-data-connection-count"
+	SiteConfigRouterIngressHostKey         string = "router-ingress-host"
+	SiteConfigRouterServiceAnnotationsKey  string = "router-service-annotations"
+	SiteConfigRouterLoadBalancerIp         string = "router-load-balancer-ip"
+	SiteConfigRouterDisableMutualTLS       string = "router-disable-mutual-tls"
 
 	// controller options
 	SiteConfigServiceControllerKey            string = "service-controller"
@@ -235,6 +236,9 @@ func (cli *VanClient) SiteConfigCreate(ctx context.Context, spec types.SiteConfi
 	if spec.Router.MaxSessionFrames != types.RouterMaxSessionFramesDefault {
 		siteConfig.Data[SiteConfigRouterMaxSessionFramesKey] = strconv.Itoa(spec.Router.MaxSessionFrames)
 	}
+	if spec.Router.DataConnectionCount != "" {
+		siteConfig.Data[SiteConfigRouterDataConnectionCountKey] = spec.Router.DataConnectionCount
+	}
 	if len(spec.Router.ServiceAnnotations) > 0 {
 		var annotations []string
 		for key, value := range spec.Router.ServiceAnnotations {
diff --git a/client/site_config_inspect.go b/client/site_config_inspect.go
index 366f24f1..71e0a8dd 100644
--- a/client/site_config_inspect.go
+++ b/client/site_config_inspect.go
@@ -228,6 +228,9 @@ func (cli *VanClient) SiteConfigInspectInNamespace(ctx context.Context, input *c
 	} else {
 		result.Spec.Router.MaxSessionFrames = types.RouterMaxSessionFramesDefault
 	}
+	if routerDataConnectionCount, ok := siteConfig.Data[SiteConfigRouterDataConnectionCountKey]; ok && routerDataConnectionCount != "" {
+		result.Spec.Router.DataConnectionCount = routerDataConnectionCount
+	}
 
 	if routerServiceAnnotations, ok := siteConfig.Data[SiteConfigRouterServiceAnnotationsKey]; ok {
 		result.Spec.Router.ServiceAnnotations = asMap(splitWithEscaping(routerServiceAnnotations, ',', '\\'))
diff --git a/cmd/skupper/skupper_kube_site.go b/cmd/skupper/skupper_kube_site.go
index f7352fe7..8f4712b5 100644
--- a/cmd/skupper/skupper_kube_site.go
+++ b/cmd/skupper/skupper_kube_site.go
@@ -140,6 +140,7 @@ func (s *SkupperKubeSite) CreateFlags(cmd *cobra.Command) {
 	cmd.Flags().StringVar(&routerCreateOpts.Router.IngressHost, "router-ingress-host", "", "Host through which node is accessible when using nodeport as ingress.")
 	cmd.Flags().StringVar(&routerCreateOpts.Router.LoadBalancerIp, "router-load-balancer-ip", "", "Load balancer ip that will be used for router service, if supported by cloud provider")
 	cmd.Flags().BoolVarP(&routerCreateOpts.Router.DisableMutualTLS, "router-disable-mutual-tls", "", false, "Disables client authentication through TLS of sites linking to this site")
+	cmd.Flags().StringVarP(&routerCreateOpts.Router.DataConnectionCount, "router-data-connection-count", "", "", "Configures the number of data connections the router will use when linking to other routers")
 
 	cmd.Flags().StringVar(&routerCreateOpts.Controller.Cpu, "controller-cpu", "", "CPU request for controller pods")
 	cmd.Flags().StringVar(&routerCreateOpts.Controller.Memory, "controller-memory", "", "Memory request for controller pods")
diff --git a/pkg/flow/record.go b/pkg/flow/record.go
index b75c18c1..9e4c8ce9 100644
--- a/pkg/flow/record.go
+++ b/pkg/flow/record.go
@@ -440,6 +440,7 @@ type QueryParams struct {
 	TimeRangeStart     uint64            `json:"timeRangeStart"`
 	TimeRangeEnd       uint64            `json:"timeRangeEnd"`
 	TimeRangeOperation TimeRangeRelation `json:"timeRangeOperation"`
+	State              RecordState       `json:"state"`
 }
 
 func getQueryParams(url *url.URL) QueryParams {
@@ -453,6 +454,7 @@ func getQueryParams(url *url.URL) QueryParams {
 		TimeRangeStart:     now - (15 * oneMinute),
 		TimeRangeEnd:       now,
 		TimeRangeOperation: intersects,
+		State:              all,
 	}
 
 	for k, v := range url.Query() {
@@ -499,6 +501,18 @@ func getQueryParams(url *url.URL) QueryParams {
 			default:
 				qp.TimeRangeOperation = intersects
 			}
+		case "state":
+			recordState := v[0]
+			switch recordState {
+			case "all":
+				qp.State = all
+			case "active":
+				qp.State = active
+			case "terminated":
+				qp.State = terminated
+			default:
+				qp.State = all
+			}
 		default:
 			qp.FilterFields[cases.Title(language.Und, cases.NoLower).String(k)] = v[0]
 		}
@@ -533,16 +547,30 @@ const (
 	within
 )
 
+type RecordState int
+
+const (
+	all RecordState = iota
+	active
+	terminated
+)
+
 func (base *Base) TimeRangeValid(qp QueryParams) bool {
-	switch qp.TimeRangeOperation {
-	case intersects:
-		return !(base.EndTime != 0 && base.EndTime < qp.TimeRangeStart || base.StartTime > qp.TimeRangeEnd)
-	case contains:
-		return base.StartTime <= qp.TimeRangeStart && (base.EndTime == 0 || base.EndTime >= qp.TimeRangeEnd)
-	case within:
-		return base.StartTime >= qp.TimeRangeStart && (base.EndTime != 0 && base.EndTime <= qp.TimeRangeEnd)
-	default:
+	if qp.State == active && base.EndTime != 0 {
 		return false
+	} else if qp.State == terminated && base.EndTime == 0 {
+		return false
+	} else {
+		switch qp.TimeRangeOperation {
+		case intersects:
+			return !(base.EndTime != 0 && base.EndTime < qp.TimeRangeStart || base.StartTime > qp.TimeRangeEnd)
+		case contains:
+			return base.StartTime <= qp.TimeRangeStart && (base.EndTime == 0 || base.EndTime >= qp.TimeRangeEnd)
+		case within:
+			return base.StartTime >= qp.TimeRangeStart && (base.EndTime != 0 && base.EndTime <= qp.TimeRangeEnd)
+		default:
+			return false
+		}
 	}
 }
 
diff --git a/pkg/qdr/qdr.go b/pkg/qdr/qdr.go
index 2b03198c..681338a9 100644
--- a/pkg/qdr/qdr.go
+++ b/pkg/qdr/qdr.go
@@ -69,6 +69,7 @@ func InitialConfig(id string, siteId string, version string, edge bool, helloAge
 
 func InitialConfigSkupperRouter(id string, siteId string, version string, edge bool, helloAge int, options types.RouterOptions) RouterConfig {
 	routerConfig := InitialConfig(id, siteId, version, edge, helloAge)
+	routerConfig.Metadata.DataConnectionCount = options.DataConnectionCount
 
 	if options.Logging != nil {
 		ConfigureRouterLogging(&routerConfig, options.Logging)
@@ -411,10 +412,11 @@ const (
 )
 
 type RouterMetadata struct {
-	Id                 string `json:"id,omitempty"`
-	Mode               Mode   `json:"mode,omitempty"`
-	HelloMaxAgeSeconds string `json:"helloMaxAgeSeconds,omitempty"`
-	Metadata           string `json:"metadata,omitempty"`
+	Id                  string `json:"id,omitempty"`
+	Mode                Mode   `json:"mode,omitempty"`
+	HelloMaxAgeSeconds  string `json:"helloMaxAgeSeconds,omitempty"`
+	DataConnectionCount string `json:"dataConnectionCount,omitempty"`
+	Metadata            string `json:"metadata,omitempty"`
 }
 
 type SslProfile struct {


Test patch:
diff --git a/pkg/flow/record_test.go b/pkg/flow/record_test.go
index 70273074..00511dbc 100644
--- a/pkg/flow/record_test.go
+++ b/pkg/flow/record_test.go
@@ -270,6 +270,93 @@ func TestTimeRange(t *testing.T) {
 	}
 }
 
+func TestRecordState(t *testing.T) {
+	type test struct {
+		name               string
+		startTime          uint64
+		endTime            uint64
+		queryParams        QueryParams
+		timeRangeStart     uint64
+		timeRangeEnd       uint64
+		timeRangeOperation TimeRangeRelation
+		state              RecordState
+		result             bool
+	}
+
+	testTable := []test{
+		// A[2,3]
+		{
+			name:      "A-all",
+			startTime: 2,
+			endTime:   15,
+			queryParams: QueryParams{
+				TimeRangeStart:     1,
+				TimeRangeEnd:       20,
+				TimeRangeOperation: intersects,
+				State:              all,
+			},
+			result: true,
+		},
+		{
+			name:      "A-active",
+			startTime: 2,
+			endTime:   0,
+			queryParams: QueryParams{
+				TimeRangeStart:     1,
+				TimeRangeEnd:       20,
+				TimeRangeOperation: intersects,
+				State:              active,
+			},
+			result: true,
+		},
+		{
+			name:      "A-not-active",
+			startTime: 2,
+			endTime:   15,
+			queryParams: QueryParams{
+				TimeRangeStart:     1,
+				TimeRangeEnd:       20,
+				TimeRangeOperation: intersects,
+				State:              active,
+			},
+			result: false,
+		},
+		{
+			name:      "A-terminated",
+			startTime: 2,
+			endTime:   3,
+			queryParams: QueryParams{
+				TimeRangeStart:     1,
+				TimeRangeEnd:       20,
+				TimeRangeOperation: intersects,
+				State:              terminated,
+			},
+			result: true,
+		},
+		{
+			name:      "A-not-terminated",
+			startTime: 2,
+			endTime:   0,
+			queryParams: QueryParams{
+				TimeRangeStart:     1,
+				TimeRangeEnd:       20,
+				TimeRangeOperation: intersects,
+				State:              terminated,
+			},
+			result: false,
+		},
+	}
+
+	for _, test := range testTable {
+		base := Base{
+			StartTime: test.startTime,
+			EndTime:   test.endTime,
+		}
+		result := base.TimeRangeValid(test.queryParams)
+		assert.Equal(t, test.result, result, test.name)
+	}
+}
+
 func TestParameters(t *testing.T) {
 	type test struct {
 		values      map[string]string