@@ -123,6 +123,13 @@ type consumeFunc func(ctx context.Context, from uint64, entries []storage.Sequen
123123
124124// Config holds GCP project and resource configuration for a storage instance.
125125type Config struct {
126+ // GCSClient will be used to interact with GCS. If unset, Tessera will create one.
127+ GCSClient * gcs.Client
128+ // SpannerClient will be used to interact with Spanner. If unset, Tessera will create one.
129+ SpannerClient * spanner.Client
130+ // HTTPClient will be used for other HTTP requests. If unset, Tessera will use the net/http DefaultClient.
131+ HTTPClient * http.Client
132+
126133 // Bucket is the name of the GCS bucket to use for storing log state.
127134 Bucket string
128135 // BucketPrefix is an optional prefix to prepend to all log resource paths.
@@ -134,6 +141,9 @@ type Config struct {
134141
135142// New creates a new instance of the GCP based Storage.
136143func New (ctx context.Context , cfg Config ) (tessera.Driver , error ) {
144+ if cfg .HTTPClient == nil {
145+ cfg .HTTPClient = http .DefaultClient
146+ }
137147 return & Storage {
138148 cfg : cfg ,
139149 }, nil
@@ -192,17 +202,31 @@ func (lr *LogReader) NextIndex(ctx context.Context) (uint64, error) {
192202
193203// Appender creates a new tessera.Appender lifecycle object.
194204func (s * Storage ) Appender (ctx context.Context , opts * tessera.AppendOptions ) (* tessera.Appender , tessera.LogReader , error ) {
195- c , err := gcs .NewClient (ctx , gcs .WithJSONReads ())
196- if err != nil {
197- return nil , nil , fmt .Errorf ("failed to create GCS client: %v" , err )
205+ if s .cfg .GCSClient == nil {
206+ var err error
207+ s .cfg .GCSClient , err = gcs .NewClient (ctx , gcs .WithJSONReads ())
208+ if err != nil {
209+ return nil , nil , fmt .Errorf ("failed to create GCS client: %v" , err )
210+ }
198211 }
199212 gs := & gcsStorage {
200- gcsClient : c ,
213+ gcsClient : s . cfg . GCSClient ,
201214 bucket : s .cfg .Bucket ,
202215 bucketPrefix : s .cfg .BucketPrefix ,
203216 }
204217
205- seq , err := newSpannerCoordinator (ctx , s .cfg .Spanner , uint64 (opts .PushbackMaxOutstanding ()))
218+ var err error
219+ if s .cfg .SpannerClient == nil {
220+ s .cfg .SpannerClient , err = spanner .NewClient (ctx , s .cfg .Spanner )
221+ if err != nil {
222+ return nil , nil , fmt .Errorf ("failed to connect to Spanner: %v" , err )
223+ }
224+ }
225+ if err := initDB (ctx , s .cfg .Spanner ); err != nil {
226+ return nil , nil , fmt .Errorf ("failed to verify/init Spanner schema: %v" , err )
227+ }
228+
229+ seq , err := newSpannerCoordinator (ctx , s .cfg .SpannerClient , uint64 (opts .PushbackMaxOutstanding ()))
206230 if err != nil {
207231 return nil , nil , fmt .Errorf ("failed to create Spanner coordinator: %v" , err )
208232 }
@@ -242,7 +266,7 @@ func (s *Storage) newAppender(ctx context.Context, o objStore, seq *spannerCoord
242266 return a .sequencer .nextIndex (ctx )
243267 },
244268 }
245- a .newCP = opts .CheckpointPublisher (reader , http . DefaultClient )
269+ a .newCP = opts .CheckpointPublisher (reader , s . cfg . HTTPClient )
246270
247271 if err := a .init (ctx ); err != nil {
248272 return nil , nil , fmt .Errorf ("failed to initialise log storage: %v" , err )
@@ -681,18 +705,11 @@ type spannerCoordinator struct {
681705
682706// newSpannerCoordinator returns a new spannerSequencer struct which uses the provided
683707// spanner resource name for its spanner connection.
684- func newSpannerCoordinator (ctx context.Context , spannerDB string , maxOutstanding uint64 ) (* spannerCoordinator , error ) {
685- dbPool , err := spanner .NewClient (ctx , spannerDB )
686- if err != nil {
687- return nil , fmt .Errorf ("failed to connect to Spanner: %v" , err )
688- }
708+ func newSpannerCoordinator (ctx context.Context , dbPool * spanner.Client , maxOutstanding uint64 ) (* spannerCoordinator , error ) {
689709 r := & spannerCoordinator {
690710 dbPool : dbPool ,
691711 maxOutstanding : maxOutstanding ,
692712 }
693- if err := r .initDB (ctx , spannerDB ); err != nil {
694- return nil , fmt .Errorf ("failed to initDB: %v" , err )
695- }
696713 if err := r .checkDataCompatibility (ctx ); err != nil {
697714 return nil , fmt .Errorf ("schema is not compatible with this version of the Tessera library: %v" , err )
698715 }
@@ -712,7 +729,7 @@ func newSpannerCoordinator(ctx context.Context, spannerDB string, maxOutstanding
712729// - IntCoord
713730// This table coordinates integration of the batches of entries stored in
714731// Seq into the committed tree state.
715- func ( s * spannerCoordinator ) initDB (ctx context.Context , spannerDB string ) error {
732+ func initDB (ctx context.Context , spannerDB string ) error {
716733 return createAndPrepareTables (
717734 ctx , spannerDB ,
718735 []string {
@@ -1217,12 +1234,25 @@ func (s *gcsStorage) deleteObjectsWithPrefix(ctx context.Context, objPrefix stri
12171234
12181235// MigrationWriter creates a new GCP storage for the MigrationTarget lifecycle mode.
12191236func (s * Storage ) MigrationWriter (ctx context.Context , opts * tessera.MigrationOptions ) (migrate.MigrationWriter , tessera.LogReader , error ) {
1220- c , err := gcs .NewClient (ctx , gcs .WithJSONReads ())
1221- if err != nil {
1222- return nil , nil , fmt .Errorf ("failed to create GCS client: %v" , err )
1237+ var err error
1238+ if s .cfg .GCSClient == nil {
1239+ s .cfg .GCSClient , err = gcs .NewClient (ctx , gcs .WithJSONReads ())
1240+ if err != nil {
1241+ return nil , nil , fmt .Errorf ("failed to create GCS client: %v" , err )
1242+ }
1243+ }
1244+
1245+ if s .cfg .SpannerClient == nil {
1246+ s .cfg .SpannerClient , err = spanner .NewClient (ctx , s .cfg .Spanner )
1247+ if err != nil {
1248+ return nil , nil , fmt .Errorf ("failed to connect to Spanner: %v" , err )
1249+ }
1250+ }
1251+ if err := initDB (ctx , s .cfg .Spanner ); err != nil {
1252+ return nil , nil , fmt .Errorf ("failed to verify/init Spanner schema: %v" , err )
12231253 }
12241254
1225- seq , err := newSpannerCoordinator (ctx , s .cfg .Spanner , 0 )
1255+ seq , err := newSpannerCoordinator (ctx , s .cfg .SpannerClient , 0 )
12261256 if err != nil {
12271257 return nil , nil , fmt .Errorf ("failed to create Spanner sequencer: %v" , err )
12281258 }
@@ -1233,7 +1263,7 @@ func (s *Storage) MigrationWriter(ctx context.Context, opts *tessera.MigrationOp
12331263 sequencer : seq ,
12341264 logStore : & logResourceStore {
12351265 objStore : & gcsStorage {
1236- gcsClient : c ,
1266+ gcsClient : s . cfg . GCSClient ,
12371267 bucket : s .cfg .Bucket ,
12381268 bucketPrefix : s .cfg .BucketPrefix ,
12391269 },
0 commit comments