Files
open-cluster-management/pkg/server/services/tokenrequest/tokenreqeust.go
Wei Liu 5740147dba
Some checks failed
Post / images (amd64, placement) (push) Failing after 46s
Post / images (amd64, registration) (push) Failing after 42s
Post / images (amd64, registration-operator) (push) Failing after 39s
Post / images (amd64, work) (push) Failing after 39s
Post / images (arm64, addon-manager) (push) Failing after 41s
Post / images (arm64, placement) (push) Failing after 40s
Post / images (arm64, registration) (push) Failing after 41s
Post / images (arm64, registration-operator) (push) Failing after 40s
Post / images (arm64, work) (push) Failing after 42s
Post / images (amd64, addon-manager) (push) Failing after 7m44s
Post / image manifest (addon-manager) (push) Has been skipped
Post / image manifest (placement) (push) Has been skipped
Post / image manifest (registration) (push) Has been skipped
Post / image manifest (registration-operator) (push) Has been skipped
Post / image manifest (work) (push) Has been skipped
Post / trigger clusteradm e2e (push) Has been skipped
Post / coverage (push) Failing after 10m19s
Scorecard supply-chain security / Scorecard analysis (push) Failing after 23s
Close stale issues and PRs / stale (push) Successful in 44s
add token request service (#1339)
Signed-off-by: Wei Liu <liuweixa@redhat.com>
2026-01-20 03:19:41 +00:00

124 lines
4.0 KiB
Go

package tokenrequest
import (
"context"
"fmt"
"time"
cloudevents "github.com/cloudevents/sdk-go/v2"
authenticationv1 "k8s.io/api/authentication/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
sace "open-cluster-management.io/sdk-go/pkg/cloudevents/clients/serviceaccount"
"open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types"
"open-cluster-management.io/sdk-go/pkg/cloudevents/server"
"open-cluster-management.io/ocm/pkg/server/services"
)
var (
// TokenCacheTTL is the time-to-live for cached token responses
// Tokens are cached temporarily until the agent retrieves them
TokenCacheTTL = 30 * time.Second
)
type TokenRequestService struct {
client kubernetes.Interface
codec *sace.TokenRequestCodec
handler server.EventHandler
store cache.Store
}
// NewTokenRequestService creates a new TokenRequestService with a TTL-based token cache
func NewTokenRequestService(client kubernetes.Interface) server.Service {
return &TokenRequestService{
client: client,
codec: sace.NewTokenRequestCodec(),
store: cache.NewTTLStore(func(obj interface{}) (string, error) {
tokenRequest, ok := obj.(*authenticationv1.TokenRequest)
if !ok {
return "", fmt.Errorf("object is not a TokenRequest")
}
return string(tokenRequest.UID), nil
}, TokenCacheTTL),
}
}
func (t *TokenRequestService) Get(ctx context.Context, resourceID string) (*cloudevents.Event, error) {
// Get the token request from store by resourceID
obj, exists, err := t.store.GetByKey(resourceID)
if err != nil {
return nil, fmt.Errorf("failed to get token request from store: %v", err)
}
if !exists {
return nil, errors.NewNotFound(authenticationv1.Resource("tokenrequests"), resourceID)
}
tokenRequest, ok := obj.(*authenticationv1.TokenRequest)
if !ok {
return nil, fmt.Errorf("stored object is not a TokenRequest")
}
// Token will be automatically removed from cache when TTL expires
return t.codec.Encode(services.CloudEventsSourceKube, types.CloudEventsType{CloudEventsDataType: sace.TokenRequestDataType}, tokenRequest)
}
func (t *TokenRequestService) List(listOpts types.ListOptions) ([]*cloudevents.Event, error) {
// resync is not needed, so list is not required
return nil, nil
}
func (t *TokenRequestService) HandleStatusUpdate(ctx context.Context, evt *cloudevents.Event) error {
logger := klog.FromContext(ctx)
eventType, err := types.ParseCloudEventsType(evt.Type())
if err != nil {
return fmt.Errorf("failed to parse cloud event type %s, %v", evt.Type(), err)
}
tokenRequest, err := t.codec.Decode(evt)
if err != nil {
return err
}
requestID := tokenRequest.UID
logger.V(4).Info("handle token request", "namespace", tokenRequest.Namespace,
"serviceAccount", tokenRequest.Name, "requestID", requestID,
"subResource", eventType.SubResource, "actionType", eventType.Action)
switch eventType.Action {
case types.CreateRequestAction:
// Create a token for the service account
tokenResponse, err := t.client.CoreV1().ServiceAccounts(tokenRequest.Namespace).CreateToken(ctx, tokenRequest.Name, tokenRequest, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("failed to create token for service account %s/%s: %v", tokenRequest.Namespace, tokenRequest.Name, err)
}
// set request id back
tokenResponse.UID = requestID
// Cache the token response in the store for later retrieval
if err := t.store.Add(tokenResponse); err != nil {
return fmt.Errorf("failed to cache token response: %v", err)
}
// Notify the handler that the token is ready for retrieval
if err := t.handler.OnCreate(ctx, eventType.CloudEventsDataType, string(tokenRequest.UID)); err != nil {
return fmt.Errorf("failed to notify handler: %v", err)
}
return nil
default:
return fmt.Errorf("unsupported action %s for tokenRequest %s/%s", eventType.Action, tokenRequest.Namespace, tokenRequest.Name)
}
}
func (t *TokenRequestService) RegisterHandler(ctx context.Context, handler server.EventHandler) {
t.handler = handler
}