mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
feat: Add Cloud Endpoint Sync Commands (#216)
* feat: Add cloud sync command * feat: Add pmg cloud commands * fix: Code review fixes * fix: Code review fixes * fix: Code review fixes * fix: Code review fixes * fix: Code review fixes * fix: Code review fixes
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
package audit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/safedep/dry/cloud"
|
||||
"github.com/safedep/dry/cloud/endpointsync"
|
||||
"github.com/safedep/dry/log"
|
||||
"github.com/safedep/pmg/config"
|
||||
appVersion "github.com/safedep/pmg/internal/version"
|
||||
)
|
||||
|
||||
// SyncClientBundle holds a SyncClient and its underlying cloud client.
|
||||
// Callers must call Close() when done.
|
||||
type SyncClientBundle struct {
|
||||
syncClient *endpointsync.SyncClient
|
||||
cloudClient *cloud.Client
|
||||
keychainResolver cloud.CloseableCredentialResolver
|
||||
}
|
||||
|
||||
// Sync delivers pending events from the WAL to SafeDep Cloud.
|
||||
func (b *SyncClientBundle) Sync(ctx context.Context) (int, error) {
|
||||
return b.syncClient.Sync(ctx)
|
||||
}
|
||||
|
||||
func (b *SyncClientBundle) Close() error {
|
||||
var errs []error
|
||||
if b.syncClient != nil {
|
||||
if err := b.syncClient.Close(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if b.cloudClient != nil {
|
||||
if err := b.cloudClient.Close(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if b.keychainResolver != nil {
|
||||
if err := b.keychainResolver.Close(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
// NewSyncClientBundle creates an authenticated SyncClient connected to SafeDep Cloud.
|
||||
func NewSyncClientBundle(cfg *config.RuntimeConfig) (*SyncClientBundle, error) {
|
||||
// Build credential resolver chain: keychain first, env fallback.
|
||||
var resolvers []cloud.CredentialResolver
|
||||
var keychainResolver cloud.CloseableCredentialResolver
|
||||
|
||||
keychainResolver, err := cloud.NewKeychainCredentialResolver(cloud.CredentialTypeAPIKey)
|
||||
if err != nil {
|
||||
log.Debugf("Keychain credential resolver not available, skipping: %v", err)
|
||||
} else {
|
||||
resolvers = append(resolvers, keychainResolver)
|
||||
}
|
||||
|
||||
envResolver, err := cloud.NewEnvCredentialResolver()
|
||||
if err != nil {
|
||||
log.Debugf("Env credential resolver not available, skipping: %v", err)
|
||||
} else {
|
||||
resolvers = append(resolvers, envResolver)
|
||||
}
|
||||
|
||||
if len(resolvers) == 0 {
|
||||
if keychainResolver != nil {
|
||||
if closeErr := keychainResolver.Close(); closeErr != nil {
|
||||
log.Warnf("failed to close keychain resolver: %v", closeErr)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no credential resolvers available")
|
||||
}
|
||||
|
||||
chain := cloud.NewChainCredentialResolver(resolvers...)
|
||||
creds, err := chain.Resolve()
|
||||
if err != nil {
|
||||
if keychainResolver != nil {
|
||||
if closeErr := keychainResolver.Close(); closeErr != nil {
|
||||
log.Warnf("failed to close keychain resolver: %v", closeErr)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("failed to resolve cloud credentials: %w", err)
|
||||
}
|
||||
|
||||
cloudClient, err := cloud.NewDataPlaneClient("pmg", creds)
|
||||
if err != nil {
|
||||
if keychainResolver != nil {
|
||||
if closeErr := keychainResolver.Close(); closeErr != nil {
|
||||
log.Warnf("failed to close keychain resolver: %v", closeErr)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("failed to create data plane client: %w", err)
|
||||
}
|
||||
|
||||
transport := endpointsync.NewGrpcTransport(cloudClient.Connection())
|
||||
|
||||
var identityOpts []endpointsync.EndpointIdentityOption
|
||||
if cfg.Config.Cloud.EndpointID != "" {
|
||||
identityOpts = append(identityOpts, endpointsync.WithEndpointID(cfg.Config.Cloud.EndpointID))
|
||||
}
|
||||
|
||||
identity := endpointsync.NewEndpointIdentityResolver(identityOpts...)
|
||||
|
||||
toolVersion := appVersion.Version
|
||||
if toolVersion == "" {
|
||||
toolVersion = "dev"
|
||||
}
|
||||
|
||||
syncClient, err := endpointsync.NewSyncClient("pmg", toolVersion, transport, identity,
|
||||
endpointsync.WithWALPath(cfg.CloudSyncDBPath()))
|
||||
if err != nil {
|
||||
if closeErr := cloudClient.Close(); closeErr != nil {
|
||||
log.Warnf("failed to close cloud client after sync client init failure: %v", closeErr)
|
||||
}
|
||||
if keychainResolver != nil {
|
||||
if closeErr := keychainResolver.Close(); closeErr != nil {
|
||||
log.Warnf("failed to close keychain resolver: %v", closeErr)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("failed to create sync client: %w", err)
|
||||
}
|
||||
|
||||
return &SyncClientBundle{
|
||||
syncClient: syncClient,
|
||||
cloudClient: cloudClient,
|
||||
keychainResolver: keychainResolver,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user