This repository has been archived by the owner on Mar 11, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 26
feat: call cluster service to create identity cluster relation while creating user #745
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
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 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 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 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 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 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 |
---|---|---|
|
@@ -13,7 +13,15 @@ import ( | |
"github.com/fabric8-services/fabric8-auth/application/service/base" | ||
servicecontext "github.com/fabric8-services/fabric8-auth/application/service/context" | ||
"github.com/fabric8-services/fabric8-auth/cluster" | ||
"github.com/fabric8-services/fabric8-auth/goasupport" | ||
"github.com/fabric8-services/fabric8-auth/log" | ||
"github.com/fabric8-services/fabric8-auth/rest" | ||
clusterclient "github.com/fabric8-services/fabric8-cluster-client/cluster" | ||
goaclient "github.com/goadesign/goa/client" | ||
"github.com/pkg/errors" | ||
"github.com/satori/go.uuid" | ||
"net/http" | ||
"net/url" | ||
) | ||
|
||
type clusterServiceConfig interface { | ||
|
@@ -77,6 +85,64 @@ func (s *clusterService) Stop() { | |
} | ||
} | ||
|
||
// LinkIdentityToCluster links Identity To Cluster using Cluster URL | ||
func (s *clusterService) LinkIdentityToCluster(ctx context.Context, identityID uuid.UUID, clusterURL string, options ...rest.HTTPClientOption) error { | ||
signer := newJWTSASigner(ctx, s.config, options...) | ||
remoteClusterService, err := signer.createSignedClient() | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to create JWT signer for cluster service") | ||
} | ||
identityToClusterData := &clusterclient.LinkIdentityToClusterData{ | ||
ClusterURL: clusterURL, | ||
IdentityID: identityID.String(), | ||
} | ||
res, err := remoteClusterService.LinkIdentityToClusterClusters(goasupport.ForwardContextRequestID(ctx), clusterclient.LinkIdentityToClusterClustersPath(), identityToClusterData) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to link identity %s to cluster having url %s", identityID, clusterURL) | ||
} | ||
defer rest.CloseResponse(res) | ||
bodyString := rest.ReadBody(res.Body) // To prevent FDs leaks | ||
if res.StatusCode != http.StatusNoContent { | ||
log.Error(ctx, map[string]interface{}{ | ||
"identity_id": identityID, | ||
"cluster_url": clusterURL, | ||
"response_status": res.Status, | ||
"response_body": bodyString, | ||
}, "unable to link identity to cluster in cluster management service") | ||
return errors.Errorf("failed to link identity to cluster in cluster management service. Response status: %s. Response body: %s", res.Status, bodyString) | ||
} | ||
return nil | ||
} | ||
|
||
// UnlinkIdentityFromCluster removes linked Identity from Cluster using Cluster URL | ||
func (s *clusterService) UnlinkIdentityFromCluster(ctx context.Context, identityID uuid.UUID, clusterURL string, options ...rest.HTTPClientOption) error { | ||
signer := newJWTSASigner(ctx, s.config, options...) | ||
remoteClusterService, err := signer.createSignedClient() | ||
if err != nil { | ||
return err | ||
} | ||
identityToClusterData := &clusterclient.UnLinkIdentityToClusterdata{ | ||
ClusterURL: clusterURL, | ||
IdentityID: identityID.String(), | ||
} | ||
res, err := remoteClusterService.RemoveIdentityToClusterLinkClusters(goasupport.ForwardContextRequestID(ctx), clusterclient.RemoveIdentityToClusterLinkClustersPath(), identityToClusterData) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to unlink identity %s from cluster having url %s", identityID, clusterURL) | ||
} | ||
defer rest.CloseResponse(res) | ||
bodyString := rest.ReadBody(res.Body) // To prevent FDs leaks | ||
if res.StatusCode != http.StatusNoContent { | ||
log.Error(ctx, map[string]interface{}{ | ||
"identity_id": identityID, | ||
"cluster_url": clusterURL, | ||
"response_status": res.Status, | ||
"response_body": bodyString, | ||
}, "unable to remove identity cluster relationship in cluster management service") | ||
return errors.Errorf("failed to unlink identity to cluster in cluster management service. Response status: %s. Response body: %s", res.Status, bodyString) | ||
} | ||
return nil | ||
} | ||
|
||
// Start initializes the default Cluster cache if it's not initialized already | ||
// Cache initialization loads the list of clusters from the cluster management service and starts regular cache refresher | ||
func Start(ctx context.Context, factory service.ClusterCacheFactory, options ...rest.HTTPClientOption) (bool, error) { | ||
|
@@ -93,10 +159,10 @@ func Start(ctx context.Context, factory service.ClusterCacheFactory, options ... | |
} else { | ||
clusterCache = nil | ||
} | ||
return (clusterCache != nil && started == uint32(1)), err | ||
return clusterCache != nil && started == uint32(1), err | ||
} | ||
} | ||
return (clusterCache != nil && started == uint32(1)), nil | ||
return clusterCache != nil && started == uint32(1), nil | ||
} | ||
|
||
// Clusters converts the given cluster map to an array slice | ||
|
@@ -109,11 +175,60 @@ func Clusters(clusters map[string]cluster.Cluster) []cluster.Cluster { | |
} | ||
|
||
func ClusterByURL(clusters map[string]cluster.Cluster, url string) *cluster.Cluster { | ||
for apiURL, cluster := range clusters { | ||
for apiURL, c := range clusters { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good work in avoiding var names with package names 👍 |
||
if strings.HasPrefix(rest.AddTrailingSlashToURL(url), apiURL) { | ||
return &cluster | ||
return &c | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type saSigner interface { | ||
createSignedClient() (*clusterclient.Client, error) | ||
} | ||
|
||
type jwtSASigner struct { | ||
ctx context.Context | ||
config clusterConfig | ||
options []rest.HTTPClientOption | ||
} | ||
|
||
func newJWTSASigner(ctx context.Context, config clusterConfig, options ...rest.HTTPClientOption) saSigner { | ||
return &jwtSASigner{ctx, config, options} | ||
} | ||
|
||
// CreateSignedClient creates a client with a JWT signer which uses the Auth Service Account token | ||
func (c jwtSASigner) createSignedClient() (*clusterclient.Client, error) { | ||
cln, err := c.createClient(c.ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
m, err := manager.DefaultManager(c.config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
signer := m.AuthServiceAccountSigner() | ||
cln.SetJWTSigner(signer) | ||
return cln, nil | ||
} | ||
|
||
func (c jwtSASigner) createClient(ctx context.Context) (*clusterclient.Client, error) { | ||
u, err := url.Parse(c.config.GetClusterServiceURL()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
httpClient := http.DefaultClient | ||
|
||
if c.options != nil { | ||
for _, opt := range c.options { | ||
opt(httpClient) | ||
} | ||
} | ||
cln := clusterclient.New(goaclient.HTTPClientDoer(httpClient)) | ||
|
||
cln.Host = u.Host | ||
cln.Scheme = u.Scheme | ||
return cln, nil | ||
} |
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.
if this code tries to start the cache only once, then maybe https://golang.org/pkg/sync/#Once.Do would be more appropriate ?
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.
This code can start the cache multiple times. It should initialize the cache successfully only once. But if it failed then it should keep trying. This is why we can't use
once.Do()
here.And initialization can fail during auth service startup if cluster service is not ready yet (since it may be waiting for Auth service to start).
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.
ok