Skip to content

Commit c44a363

Browse files
adds test facilities for testing ER connections/OIDC token updates (#809)
* adds test facilities for testing ER connections/OIDC token updates * lint fixes * bump version
1 parent b4e7dfa commit c44a363

File tree

3 files changed

+131
-27
lines changed

3 files changed

+131
-27
lines changed

ziti/client.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,3 +514,24 @@ func (self *CtrlClient) supportsSetOfConfigTypesOnServiceList() bool {
514514
}
515515
return self.supportsConfigTypesOnServiceList.Load()
516516
}
517+
518+
// GetAvailableERs retrieves edge routers accessible to the current identity from the controller.
519+
// Returns detailed router information including supported protocols and connection addresses
520+
// for establishing data plane connections.
521+
func (self *CtrlClient) GetAvailableERs() ([]*rest_model.CurrentIdentityEdgeRouterDetail, error) {
522+
params := current_identity.NewGetCurrentIdentityEdgeRoutersParams()
523+
524+
var ers []*rest_model.CurrentIdentityEdgeRouterDetail
525+
526+
resp, err := self.API.CurrentIdentity.GetCurrentIdentityEdgeRouters(params, self.GetCurrentApiSession())
527+
528+
if err != nil {
529+
return nil, rest_util.WrapErr(err)
530+
}
531+
532+
ers = make([]*rest_model.CurrentIdentityEdgeRouterDetail, 0, *resp.Payload.Meta.Pagination.TotalCount)
533+
534+
ers = append(ers, resp.Payload.Data...)
535+
536+
return ers, nil
537+
}

ziti/sdkinfo/build_info.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ziti/ziti.go

Lines changed: 109 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -793,18 +793,25 @@ func (context *ContextImpl) RefreshService(serviceName string) (*rest_model.Serv
793793
return serviceDetail, nil
794794
}
795795

796-
func (context *ContextImpl) updateTokenOnAllErs(apiSession apis.ApiSession) {
796+
// updateTokenOnAllErs synchronously propagates API session tokens to all connected edge routers.
797+
// Collects and returns any router update failures as a combined error rather than logging
798+
// them individually. This enables callers to determine if token propagation was successful
799+
// across the entire router connection pool.
800+
func (context *ContextImpl) updateTokenOnAllErs(apiSession apis.ApiSession) error {
801+
var routerErrors []error
797802
if apiSession.RequiresRouterTokenUpdate() {
798803
for tpl := range context.routerConnections.IterBuffered() {
799804
erConn := tpl.Val
800805
erKey := tpl.Key
801-
go func() {
802-
if err := erConn.UpdateToken(apiSession.GetToken(), 10*time.Second); err != nil {
803-
pfxlog.Logger().WithError(err).WithField("er", erKey).Warn("error updating apiSession token to connected ER")
804-
}
805-
}()
806+
807+
if err := erConn.UpdateToken(apiSession.GetToken(), 10*time.Second); err != nil {
808+
routerError := fmt.Errorf("failed to update token on ER %s: %w", erKey, err)
809+
routerErrors = append(routerErrors, routerError)
810+
}
806811
}
807812
}
813+
814+
return errors.Join(routerErrors...)
808815
}
809816

810817
func (context *ContextImpl) runRefreshes() {
@@ -865,7 +872,11 @@ func (context *ContextImpl) runRefreshes() {
865872
refreshAt = exp.Add(-10 * time.Second)
866873
log.Debugf("apiSession refreshed, new expiration[%s]", *exp)
867874

868-
context.updateTokenOnAllErs(newApiSession)
875+
updateErr := context.updateTokenOnAllErs(newApiSession)
876+
877+
if updateErr != nil {
878+
pfxlog.Logger().WithError(updateErr).Warn("error updating current api session token on edge routers")
879+
}
869880
}
870881

871882
case <-svcRefreshTick.C:
@@ -998,6 +1009,87 @@ func (context *ContextImpl) Authenticate() error {
9981009
return context.authenticate()
9991010
}
10001011

1012+
// ConnectAllAvailableErs discovers and establishes connections to all edge routers
1013+
// accessible to the current identity. Filters routers by supported protocols and
1014+
// waits for connection attempts to complete. Returns any connection failures
1015+
// as a combined error.
1016+
func (context *ContextImpl) ConnectAllAvailableErs() error {
1017+
if err := context.ensureApiSession(); err != nil {
1018+
return fmt.Errorf("failed to establish api session (%w)", err)
1019+
}
1020+
1021+
ers, err := context.CtrlClt.GetAvailableERs()
1022+
1023+
if err != nil {
1024+
return fmt.Errorf("failed to get available edge routers: %w", err)
1025+
}
1026+
1027+
resultCh := make(chan *edgeRouterConnResult, len(ers))
1028+
1029+
for _, er := range ers {
1030+
for _, addr := range er.SupportedProtocols {
1031+
isSupported := context.options.isEdgeRouterUrlAccepted(addr)
1032+
1033+
if isSupported {
1034+
addr = strings.Replace(addr, "//", "", 1)
1035+
go context.handleConnectEdgeRouter(*er.Name, addr, resultCh)
1036+
}
1037+
1038+
}
1039+
}
1040+
1041+
expectedResults := len(ers)
1042+
1043+
var results []*edgeRouterConnResult
1044+
select {
1045+
case result := <-resultCh:
1046+
results = append(results, result)
1047+
1048+
if len(results) == expectedResults {
1049+
break
1050+
}
1051+
case <-time.After(10 * time.Second):
1052+
return fmt.Errorf("timed out waiting for edge router connections got %d expected %d", len(results), expectedResults)
1053+
}
1054+
1055+
var resultErrs []error
1056+
for _, result := range results {
1057+
if result.err != nil {
1058+
resultErrs = append(resultErrs, result.err)
1059+
}
1060+
}
1061+
1062+
return errors.Join(resultErrs...)
1063+
}
1064+
1065+
// RefreshApiSession attempts to refresh the API session and propagate the new token
1066+
// to connected edge routers. Returns two separate error values: the first indicates
1067+
// functional refresh failures (session expired, authentication errors) that affect
1068+
// the refresh operation itself, while the second contains edge router token update
1069+
// failures that don't prevent the refresh from succeeding.
1070+
func (context *ContextImpl) RefreshApiSession() (error, error) {
1071+
newApiSession, err := context.CtrlClt.Refresh()
1072+
if err == nil {
1073+
updateErrs := context.updateTokenOnAllErs(newApiSession)
1074+
return nil, updateErrs
1075+
}
1076+
1077+
unauthorizedErr := &current_api_session.GetCurrentAPISessionUnauthorized{}
1078+
if errors.As(err, &unauthorizedErr) {
1079+
logrus.Info("previous apiSession expired")
1080+
return backoff.Permanent(err), nil
1081+
}
1082+
1083+
oidcErr := &oidc.Error{}
1084+
if errors.As(err, &oidcErr) {
1085+
logrus.Info("oidc error, re-authenticating")
1086+
return backoff.Permanent(err), nil
1087+
}
1088+
1089+
logrus.WithError(err).Infof("unable to refresh apiSession, error type %T, will retry", err)
1090+
return err, nil
1091+
}
1092+
10011093
func (context *ContextImpl) RefreshApiSessionWithBackoff() error {
10021094
expBackoff := backoff.NewExponentialBackOff()
10031095

@@ -1006,26 +1098,12 @@ func (context *ContextImpl) RefreshApiSessionWithBackoff() error {
10061098
expBackoff.MaxElapsedTime = 24 * time.Hour
10071099

10081100
operation := func() error {
1009-
newApiSession, err := context.CtrlClt.Refresh()
1010-
if err == nil {
1011-
context.updateTokenOnAllErs(newApiSession)
1012-
return nil
1101+
functionalErr, erUpdateErrs := context.RefreshApiSession()
1102+
if erUpdateErrs != nil {
1103+
pfxlog.Logger().WithError(erUpdateErrs).Warn("errors during api session token update on all connected edge routers")
10131104
}
10141105

1015-
unauthorizedErr := &current_api_session.GetCurrentAPISessionUnauthorized{}
1016-
if errors.As(err, &unauthorizedErr) {
1017-
logrus.Info("previous apiSession expired")
1018-
return backoff.Permanent(err)
1019-
}
1020-
1021-
oidcErr := &oidc.Error{}
1022-
if errors.As(err, &oidcErr) {
1023-
logrus.Info("oidc error, re-authenticating")
1024-
return backoff.Permanent(err)
1025-
}
1026-
1027-
logrus.WithError(err).Infof("unable to refresh apiSession, error type %T, will retry", err)
1028-
return err
1106+
return functionalErr
10291107
}
10301108

10311109
return backoff.Retry(operation, expBackoff)
@@ -1083,7 +1161,12 @@ func (context *ContextImpl) authenticateMfa(code string) error {
10831161
if err != nil {
10841162
return err
10851163
}
1086-
context.updateTokenOnAllErs(newApiSession)
1164+
1165+
updateErr := context.updateTokenOnAllErs(newApiSession)
1166+
1167+
if updateErr != nil {
1168+
pfxlog.Logger().WithError(updateErr).Warn("error updating current api session token on edge routers")
1169+
}
10871170

10881171
apiSession := context.CtrlClt.GetCurrentApiSession()
10891172

0 commit comments

Comments
 (0)