-
Notifications
You must be signed in to change notification settings - Fork 4.6k
List Imported Services Changes #23133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
LakshmiNarayananDesikan
merged 7 commits into
main
from
admin-partitions/list-imported-services
Jan 12, 2026
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
e7bcd9c
List Imported Services Changes
LakshmiNarayananDesikan 5c91585
Added changelogs
LakshmiNarayananDesikan c049fe3
Updated changelogs
LakshmiNarayananDesikan 4018a4f
Lint fixes and code review fixes
LakshmiNarayananDesikan 4bb13f0
Consul function name sync with ENT
LakshmiNarayananDesikan 6f19150
CLI Response fix
LakshmiNarayananDesikan 26f721e
CLI Response format changes
LakshmiNarayananDesikan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| ```release-note:improvement | ||
| api: Add `consul services imported-services` and new api(/v1/exported-services) command to list services imported by partitions within a local datacenter | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| // Copyright (c) HashiCorp, Inc. | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
|
|
||
| package state | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "sort" | ||
|
|
||
| "github.com/hashicorp/go-memdb" | ||
|
|
||
| "github.com/hashicorp/consul/acl" | ||
| "github.com/hashicorp/consul/agent/structs" | ||
| "github.com/hashicorp/consul/lib" | ||
| "github.com/hashicorp/consul/proto/private/pbconfigentry" | ||
| ) | ||
|
|
||
| // importedService represents a service imported from a peer | ||
| type importedService struct { | ||
| service string | ||
| namespace string | ||
| peer string | ||
| } | ||
|
|
||
| // ImportedServicesForPartition returns the list of imported services along with their sources. | ||
| // This shows which services are being imported from peers. | ||
| func (s *Store) ImportedServicesForPartition(ws memdb.WatchSet, partition string) (uint64, []*pbconfigentry.ImportedService, error) { | ||
| tx := s.db.ReadTxn() | ||
| defer tx.Abort() | ||
|
|
||
| entMeta := acl.NewEnterpriseMetaWithPartition(partition, acl.WildcardName) | ||
| return importedServicesForPartitionTxn(tx, ws, &entMeta) | ||
| } | ||
|
|
||
| func importedServicesForPartitionTxn(tx ReadTxn, ws memdb.WatchSet, entMeta *acl.EnterpriseMeta) (uint64, []*pbconfigentry.ImportedService, error) { | ||
| maxIdx := uint64(0) | ||
|
|
||
| // Get all service intentions that have a source peer set | ||
| // This indicates services that are imported from that peer | ||
| iter, err := tx.Get(tableConfigEntries, indexID+"_prefix", ConfigEntryKindQuery{ | ||
| Kind: structs.ServiceIntentions, | ||
| EnterpriseMeta: *entMeta, | ||
| }) | ||
| if err != nil { | ||
| return 0, nil, fmt.Errorf("failed to list service intentions: %w", err) | ||
| } | ||
|
|
||
| ws.Add(iter.WatchCh()) | ||
|
|
||
| // Collect imported services from intentions | ||
| var importedServices []importedService | ||
|
|
||
| for entry := iter.Next(); entry != nil; entry = iter.Next() { | ||
| intention, ok := entry.(*structs.ServiceIntentionsConfigEntry) | ||
| if !ok { | ||
| continue | ||
| } | ||
|
|
||
| // Update max index | ||
| if intention.ModifyIndex > maxIdx { | ||
| maxIdx = intention.ModifyIndex | ||
| } | ||
|
|
||
| // Check each source intention for peer imports | ||
| for _, source := range intention.Sources { | ||
| if source.Peer != "" { | ||
| importedServices = append(importedServices, importedService{ | ||
| service: intention.Name, | ||
| namespace: intention.NamespaceOrDefault(), | ||
| peer: source.Peer, | ||
| }) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| uniqueImportedServices := getUniqueImportedServices(importedServices) | ||
| resp := prepareImportedServicesResponse(uniqueImportedServices, entMeta) | ||
|
|
||
| return lib.MaxUint64(maxIdx, 1), resp, nil | ||
| } | ||
|
|
||
| // getUniqueImportedServices removes duplicate services and sources. Services are also sorted in ascending order | ||
| func getUniqueImportedServices(importedServices []importedService) []importedService { | ||
| // Service -> SourcePeers | ||
| type serviceKey struct { | ||
| name string | ||
| namespace string | ||
| } | ||
| importedServicesMapper := make(map[serviceKey]map[string]struct{}) | ||
|
|
||
| for _, svc := range importedServices { | ||
| key := serviceKey{ | ||
| name: svc.service, | ||
| namespace: svc.namespace, | ||
| } | ||
|
|
||
| peers, ok := importedServicesMapper[key] | ||
| if !ok { | ||
| peers = make(map[string]struct{}) | ||
| importedServicesMapper[key] = peers | ||
| } | ||
| peers[svc.peer] = struct{}{} | ||
| } | ||
|
|
||
| uniqueImportedServices := make([]importedService, 0) | ||
|
|
||
| for svc, peers := range importedServicesMapper { | ||
| for peer := range peers { | ||
| uniqueImportedServices = append(uniqueImportedServices, importedService{ | ||
| service: svc.name, | ||
| namespace: svc.namespace, | ||
| peer: peer, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| sort.Slice(uniqueImportedServices, func(i, j int) bool { | ||
| if uniqueImportedServices[i].service != uniqueImportedServices[j].service { | ||
| return uniqueImportedServices[i].service < uniqueImportedServices[j].service | ||
| } | ||
| if uniqueImportedServices[i].namespace != uniqueImportedServices[j].namespace { | ||
| return uniqueImportedServices[i].namespace < uniqueImportedServices[j].namespace | ||
| } | ||
| return uniqueImportedServices[i].peer < uniqueImportedServices[j].peer | ||
| }) | ||
|
|
||
| return uniqueImportedServices | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // Copyright (c) HashiCorp, Inc. | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
|
|
||
| //go:build !consulent | ||
|
|
||
| package state | ||
|
|
||
| import ( | ||
| "github.com/hashicorp/consul/acl" | ||
| "github.com/hashicorp/consul/proto/private/pbconfigentry" | ||
| ) | ||
|
|
||
| func prepareImportedServicesResponse(importedServices []importedService, entMeta *acl.EnterpriseMeta) []*pbconfigentry.ImportedService { | ||
|
|
||
| resp := make([]*pbconfigentry.ImportedService, len(importedServices)) | ||
|
|
||
| for idx, svc := range importedServices { | ||
| resp[idx] = &pbconfigentry.ImportedService{ | ||
| Service: svc.service, | ||
| SourcePeer: svc.peer, | ||
| } | ||
| } | ||
|
|
||
| return resp | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are looping over a lot services, intentions throughout this code piece, I feel it could be a performance issue, should we rather paginate the response? that way we wont have to process each of the intention and service, etc. for every call.
Since this does not hamper the core functionality, it is not a blocker, however worth discussing once and can be planned for phase 2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will discuss and plan it for Phase 2