...

Source file src/github.com/google/certificate-transparency-go/trillian/integration/logenv.go

Documentation: github.com/google/certificate-transparency-go/trillian/integration

     1  // Copyright 2017 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package integration
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"net"
    21  	"net/http"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/google/certificate-transparency-go/trillian/ctfe"
    26  	"github.com/google/certificate-transparency-go/trillian/ctfe/configpb"
    27  	"github.com/google/trillian"
    28  	"github.com/google/trillian/client"
    29  	"github.com/google/trillian/monitoring/prometheus"
    30  	"github.com/google/trillian/testonly/integration"
    31  	"github.com/prometheus/client_golang/prometheus/promhttp"
    32  	"k8s.io/klog/v2"
    33  
    34  	stestonly "github.com/google/trillian/storage/testonly"
    35  )
    36  
    37  // CTLogEnv is a test environment that contains both a log server and a CT personality
    38  // connected to it.
    39  type CTLogEnv struct {
    40  	logEnv       *integration.LogEnv
    41  	wg           *sync.WaitGroup
    42  	ctListener   net.Listener
    43  	ctHTTPServer *http.Server
    44  	CTAddr       string
    45  }
    46  
    47  // NewCTLogEnv creates a fresh DB, log server, and CT personality.
    48  // testID should be unique to each unittest package so as to allow parallel tests.
    49  // Created logIDs will be set to cfgs.
    50  func NewCTLogEnv(ctx context.Context, cfgs []*configpb.LogConfig, numSequencers int, testID string) (*CTLogEnv, error) {
    51  	// Start log server and signer.
    52  	logEnv, err := integration.NewLogEnvWithGRPCOptions(ctx, numSequencers, nil, nil)
    53  	if err != nil {
    54  		return nil, fmt.Errorf("failed to create LogEnv: %v", err)
    55  	}
    56  
    57  	// Provision the logs.
    58  	for _, cfg := range cfgs {
    59  		tree, err := client.CreateAndInitTree(ctx,
    60  			&trillian.CreateTreeRequest{Tree: stestonly.LogTree},
    61  			logEnv.Admin, logEnv.Log)
    62  		if err != nil {
    63  			return nil, fmt.Errorf("failed to provision log %d: %v", cfg.LogId, err)
    64  		}
    65  
    66  		cfg.LogId = tree.TreeId
    67  	}
    68  
    69  	// Start the CT personality.
    70  	addr, listener, err := listen()
    71  	if err != nil {
    72  		return nil, fmt.Errorf("failed to find an unused port for CT personality: %v", err)
    73  	}
    74  	server := http.Server{Addr: addr, Handler: nil}
    75  	var wg sync.WaitGroup
    76  	wg.Add(1)
    77  	go func(env *integration.LogEnv, server *http.Server, listener net.Listener, cfgs []*configpb.LogConfig) {
    78  		defer wg.Done()
    79  		cl := trillian.NewTrillianLogClient(env.ClientConn)
    80  		for _, cfg := range cfgs {
    81  			vCfg, err := ctfe.ValidateLogConfig(cfg)
    82  			if err != nil {
    83  				klog.Fatalf("ValidateLogConfig failed: %+v: %v", cfg, err)
    84  			}
    85  			opts := ctfe.InstanceOptions{
    86  				Validated:     vCfg,
    87  				Client:        cl,
    88  				Deadline:      10 * time.Second,
    89  				MetricFactory: prometheus.MetricFactory{},
    90  				RequestLog:    new(ctfe.DefaultRequestLog),
    91  			}
    92  			inst, err := ctfe.SetUpInstance(ctx, opts)
    93  			if err != nil {
    94  				klog.Fatalf("Failed to set up log instance for %+v: %v", cfg, err)
    95  			}
    96  			for path, handler := range inst.Handlers {
    97  				http.Handle(path, handler)
    98  			}
    99  		}
   100  		http.Handle("/metrics", promhttp.Handler())
   101  		if err := server.Serve(listener); err != http.ErrServerClosed {
   102  			klog.Fatalf("server.Serve(): %v", err)
   103  		}
   104  	}(logEnv, &server, listener, cfgs)
   105  	return &CTLogEnv{
   106  		logEnv:       logEnv,
   107  		wg:           &wg,
   108  		ctListener:   listener,
   109  		ctHTTPServer: &server,
   110  		CTAddr:       addr,
   111  	}, nil
   112  }
   113  
   114  // Close shuts down the servers.
   115  func (env *CTLogEnv) Close() {
   116  	env.ctListener.Close()
   117  	env.wg.Wait()
   118  	env.logEnv.Close()
   119  }
   120  
   121  // listen opens a random high numbered port for listening.
   122  func listen() (string, net.Listener, error) {
   123  	lis, err := net.Listen("tcp", ":0")
   124  	if err != nil {
   125  		return "", nil, err
   126  	}
   127  	_, port, err := net.SplitHostPort(lis.Addr().String())
   128  	if err != nil {
   129  		return "", nil, err
   130  	}
   131  	addr := "localhost:" + port
   132  	return addr, lis, nil
   133  }
   134  

View as plain text