diff --git a/kontrol-service/go.mod b/kontrol-service/go.mod index 3b3facd..8c04523 100644 --- a/kontrol-service/go.mod +++ b/kontrol-service/go.mod @@ -7,7 +7,7 @@ toolchain go1.22.3 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/dominikbraun/graph v0.23.0 - github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240916202910-d86eaa704e51 + github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240918155021-b42fad213b93 github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240913221752-e831db545217 github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 github.com/labstack/echo/v4 v4.12.0 diff --git a/kontrol-service/go.sum b/kontrol-service/go.sum index a4bace1..cc8700b 100644 --- a/kontrol-service/go.sum +++ b/kontrol-service/go.sum @@ -81,6 +81,14 @@ github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240916193505-65d github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240916193505-65de8a373686/go.mod h1:yvON5b9BHp3yJ99+i+JUMGb985g3h6Eco+w9swS5rds= github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240916202910-d86eaa704e51 h1:D2tqOkwf8+Tj/F4u/cKmCPMy4uD0NRQDN1fempg32nY= github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240916202910-d86eaa704e51/go.mod h1:yvON5b9BHp3yJ99+i+JUMGb985g3h6Eco+w9swS5rds= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240917000055-2d661cc93e6a h1:LNl5OeNe76uzrHh3YqK3+wyYdP7F+nq+giRe1ofJr6A= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240917000055-2d661cc93e6a/go.mod h1:yvON5b9BHp3yJ99+i+JUMGb985g3h6Eco+w9swS5rds= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240917220325-f23feb2c1a12 h1:9w7yYBeNXKorc1Za9CM2ht1xWM7R64xbAeGRHAVEi1k= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240917220325-f23feb2c1a12/go.mod h1:yvON5b9BHp3yJ99+i+JUMGb985g3h6Eco+w9swS5rds= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240918152925-72b61d2a8231 h1:WNBVcZiMWQcrCF6KDhhhAJKxNyzlBq9/O+29ki43TXM= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240918152925-72b61d2a8231/go.mod h1:yvON5b9BHp3yJ99+i+JUMGb985g3h6Eco+w9swS5rds= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240918155021-b42fad213b93 h1:UiiEr4TKPFwMIXBkhbkMeh82MHNYrzn8hG7ggnhEvDQ= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240918155021-b42fad213b93/go.mod h1:yvON5b9BHp3yJ99+i+JUMGb985g3h6Eco+w9swS5rds= github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240913221752-e831db545217 h1:cCM7nTd4E6Vh/dXlRgzmyU5I7GBr7D+ImU3iMVx+Dnk= github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240913221752-e831db545217/go.mod h1:lj6oLhpXgnc9ZaulV7jysgRaeZUDPK6XiM2TxpcGRqM= github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 h1:YQTATifMUwZEtZYb0LVA7DK2pj8s71iY8rzweuUQ5+g= diff --git a/kontrol-service/gomod2nix.toml b/kontrol-service/gomod2nix.toml index baa68ba..6f69c4d 100644 --- a/kontrol-service/gomod2nix.toml +++ b/kontrol-service/gomod2nix.toml @@ -266,8 +266,8 @@ schema = 3 version = "v0.2.0" hash = "sha256-fadcWxZOORv44oak3jTxm6YcITcFxdGt4bpn869HxUE=" [mod."github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api"] - version = "v0.0.0-20240916202910-d86eaa704e51" - hash = "sha256-NcQoWjkN4yuRpAnaWb4vgwkpIdzgh+G3ng1P0VH+ynU=" + version = "v0.0.0-20240918155021-b42fad213b93" + hash = "sha256-gDzKYhstUapy2kQ6b9VQn4SSd9e280C/yhZwNhCSb/A=" [mod."github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api"] version = "v0.0.0-20240913221752-e831db545217" hash = "sha256-Y1vl6Cqpvc+b9+JPnajRGPeAXqA/XQEgcGBCXsiuTek=" diff --git a/kontrol-service/topology/toplogy.go b/kontrol-service/topology/toplogy.go index b31e091..a7d4f36 100644 --- a/kontrol-service/topology/toplogy.go +++ b/kontrol-service/topology/toplogy.go @@ -23,23 +23,39 @@ func ClusterTopology(clusterTopology *resolved.ClusterTopology, flowsClusterTopo edges := getClusterTopologyEdges(clusterTopology) - servicesToVersions := map[string][]string{} groupedServices := lo.GroupBy(topology.Services, func(item *resolved.Service) string { return item.ServiceID }) - for serviceID, services := range groupedServices { - servicesToVersions[serviceID] = lo.Map(services, func(item *resolved.Service, _ int) string { return item.Version }) - } - - nodes := lo.MapToSlice(servicesToVersions, func(key string, value []string) apiTypes.Node { + nodes := lo.MapToSlice(groupedServices, func(key string, services []*resolved.Service) apiTypes.Node { nodeType := apiTypes.Service + if services[0].IsExternal { + nodeType = apiTypes.External + } label := key - sort.Slice(value, func(i, j int) bool { - return value[i] < value[j] + versions := lo.Map(services, func(service *resolved.Service, _ int) apiTypes.NodeVersion { + var imageTag *string + if service.DeploymentSpec != nil { + imageTag = &service.DeploymentSpec.Template.Spec.Containers[0].Image + } + isBaseline := service.Version == clusterTopology.Namespace + return apiTypes.NodeVersion{ + FlowId: service.Version, + ImageTag: imageTag, + IsBaseline: isBaseline, + } + }) + sort.Slice(versions, func(i, j int) bool { + if versions[i].IsBaseline && !versions[j].IsBaseline { + return true + } else if !versions[i].IsBaseline && versions[j].IsBaseline { + return false + } else { + return versions[i].FlowId < versions[j].FlowId + } }) return apiTypes.Node{ Type: nodeType, Id: label, - Label: &label, - Versions: &value, + Label: label, + Versions: &versions, } }) @@ -47,9 +63,9 @@ func ClusterTopology(clusterTopology *resolved.ClusterTopology, flowsClusterTopo gwLabel := ingress.IngressID return apiTypes.Node{ Id: gwLabel, - Label: &gwLabel, + Label: gwLabel, Type: apiTypes.Gateway, - Versions: &[]string{}, + Versions: &[]apiTypes.NodeVersion{}, } }) diff --git a/kontrol-service/topology/topology_test.go b/kontrol-service/topology/topology_test.go index ad710a4..753d5dd 100644 --- a/kontrol-service/topology/topology_test.go +++ b/kontrol-service/topology/topology_test.go @@ -246,6 +246,8 @@ func TestServiceConfigsToTopology(t *testing.T) { clusterTopologyFlowA.FlowID = flowID for _, service := range clusterTopologyFlowA.Services { service.Version = flowID + image := service.DeploymentSpec.Template.Spec.Containers[0].Image + service.DeploymentSpec.Template.Spec.Containers[0].Image = fmt.Sprintf("%s.a", image) } clusterTopologyFlowB := deepcopy.Copy(*clusterTopology).(resolved.ClusterTopology) @@ -253,40 +255,87 @@ func TestServiceConfigsToTopology(t *testing.T) { clusterTopologyFlowB.FlowID = flowID for _, service := range clusterTopologyFlowB.Services { service.Version = flowID + image := service.DeploymentSpec.Template.Spec.Containers[0].Image + service.DeploymentSpec.Template.Spec.Containers[0].Image = fmt.Sprintf("%s.b", image) } allFlows := []resolved.ClusterTopology{} allFlows = append(allFlows, clusterTopologyFlowA, clusterTopologyFlowB) topo := ClusterTopology(clusterTopology, &allFlows) require.NotNil(t, topo) - nodes := topo.Nodes - require.Equal(t, 3, len(nodes)) + expectedAzureVoteBackImageProd := "bitnami/redis:6.0.8" + expectedAzureVoteBackImageA := "bitnami/redis:6.0.8.a" + expectedAzureVoteBackImageB := "bitnami/redis:6.0.8.b" + expectedAzurVoteFrontImageProd := "voting-app-ui" + expectedAzurVoteFrontImageA := "voting-app-ui.a" + expectedAzurVoteFrontImageB := "voting-app-ui.b" - for _, node := range nodes { - if node.Id == "azure-vote-back" || node.Id == "azure-vote-front" { - require.Equal(t, apiTypes.Service, node.Type) - require.NotEmpty(t, *node.Versions) - require.Equal(t, []string{"A", "B", "prod"}, *node.Versions) - } else if node.Id == "voting-app-lb" { - require.Equal(t, apiTypes.Gateway, node.Type) - require.Empty(t, *node.Versions) - } else { - t.Errorf("Invalid node ID %s", node.Id) - return - } - } - - edges := topo.Edges - require.Equal(t, 2, len(edges)) + require.Equal(t, + []apiTypes.Node{ + apiTypes.Node{ + Id: "azure-vote-back", + Label: "azure-vote-back", + Type: apiTypes.Service, + Versions: &[]apiTypes.NodeVersion{ + apiTypes.NodeVersion{ + FlowId: "prod", + ImageTag: &expectedAzureVoteBackImageProd, + IsBaseline: true, + }, + apiTypes.NodeVersion{ + FlowId: "A", + ImageTag: &expectedAzureVoteBackImageA, + IsBaseline: false, + }, + apiTypes.NodeVersion{ + FlowId: "B", + ImageTag: &expectedAzureVoteBackImageB, + IsBaseline: false, + }, + }, + }, + apiTypes.Node{ + Id: "azure-vote-front", + Label: "azure-vote-front", + Type: apiTypes.Service, + Versions: &[]apiTypes.NodeVersion{ + apiTypes.NodeVersion{ + FlowId: "prod", + ImageTag: &expectedAzurVoteFrontImageProd, + IsBaseline: true, + }, + apiTypes.NodeVersion{ + FlowId: "A", + ImageTag: &expectedAzurVoteFrontImageA, + IsBaseline: false, + }, + apiTypes.NodeVersion{ + FlowId: "B", + ImageTag: &expectedAzurVoteFrontImageB, + IsBaseline: false, + }, + }, + }, + apiTypes.Node{ + Id: "voting-app-lb", + Label: "voting-app-lb", + Type: apiTypes.Gateway, + Versions: &[]apiTypes.NodeVersion{}, + }, + }, + topo.Nodes) - for _, edge := range edges { - if edge.Source == "voting-app-lb" { - require.Equal(t, "azure-vote-front", edge.Target) - } else if edge.Source == "azure-vote-front" { - require.Equal(t, "azure-vote-back", edge.Target) - } else { - t.Errorf("Invalid source %s", edge.Source) - return - } - } + require.Equal(t, + []apiTypes.Edge{ + apiTypes.Edge{ + Source: "azure-vote-front", + Target: "azure-vote-back", + }, + apiTypes.Edge{ + Source: "voting-app-lb", + Target: "azure-vote-front", + }, + }, + topo.Edges, + ) }