github.com/mre-fog/trillianxx@v1.1.2-0.20180615153820-ae375a99d36a/client/admin.go (about)

     1  // Copyright 2018 Google Inc. 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 client
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"time"
    21  
    22  	"github.com/golang/glog"
    23  	"github.com/google/trillian"
    24  	"github.com/google/trillian/client/backoff"
    25  	"google.golang.org/grpc/codes"
    26  	"google.golang.org/grpc/status"
    27  )
    28  
    29  // CreateAndInitTree uses the adminClient and mapClient to create the tree
    30  // described by req.
    31  // If req describes a MAP tree, then this function will also call the InitMap
    32  // function using mapClient.
    33  // Internally, the function will continue to retry failed requests until either
    34  // the tree is created (and if necessary, initialised) successfully, or ctx is
    35  // cancelled.
    36  func CreateAndInitTree(
    37  	ctx context.Context,
    38  	req *trillian.CreateTreeRequest,
    39  	adminClient trillian.TrillianAdminClient,
    40  	mapClient trillian.TrillianMapClient,
    41  	logClient trillian.TrillianLogClient) (*trillian.Tree, error) {
    42  
    43  	b := &backoff.Backoff{
    44  		Min:    100 * time.Millisecond,
    45  		Max:    10 * time.Second,
    46  		Factor: 2,
    47  		Jitter: true,
    48  	}
    49  
    50  	var tree *trillian.Tree
    51  	err := b.Retry(ctx, func() error {
    52  		glog.Info("CreateTree...")
    53  		var err error
    54  		tree, err = adminClient.CreateTree(ctx, req)
    55  		if err != nil {
    56  			if s, ok := status.FromError(err); ok && s.Code() == codes.Unavailable {
    57  				glog.Errorf("Admin server unavailable: %v", err)
    58  				return err
    59  			}
    60  			glog.Errorf("failed to CreateTree(%+v): %T %v", req, err, err)
    61  			return err
    62  		}
    63  		return nil
    64  	})
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	switch tree.TreeType {
    70  	case trillian.TreeType_MAP:
    71  		if err := InitMap(ctx, tree, mapClient); err != nil {
    72  			return nil, err
    73  		}
    74  	case trillian.TreeType_LOG, trillian.TreeType_PREORDERED_LOG:
    75  		if err := InitLog(ctx, tree, logClient); err != nil {
    76  			return nil, err
    77  		}
    78  	default:
    79  		return nil, fmt.Errorf("Don't know how or whether to initialise tree type %v", tree.TreeType)
    80  	}
    81  
    82  	return tree, nil
    83  }
    84  
    85  // InitMap initialises a freshly created Map tree.
    86  func InitMap(ctx context.Context, tree *trillian.Tree, mapClient trillian.TrillianMapClient) error {
    87  	if tree.TreeType != trillian.TreeType_MAP {
    88  		return fmt.Errorf("InitMap called with tree of type %v", tree.TreeType)
    89  	}
    90  
    91  	b := &backoff.Backoff{
    92  		Min:    100 * time.Millisecond,
    93  		Max:    10 * time.Second,
    94  		Factor: 2,
    95  		Jitter: true,
    96  	}
    97  
    98  	err := b.Retry(ctx, func() error {
    99  		glog.Infof("Initialising Map %x...", tree.TreeId)
   100  		req := &trillian.InitMapRequest{MapId: tree.TreeId}
   101  		resp, err := mapClient.InitMap(ctx, req)
   102  		if err != nil {
   103  			switch s, ok := status.FromError(err); {
   104  			case ok && s.Code() == codes.Unavailable:
   105  				glog.Errorf("Map server unavailable: %v", err)
   106  				return err
   107  			case ok && s.Code() == codes.AlreadyExists:
   108  				glog.Warningf("Bizarrely, the just-created Map (%x) is already initialised!: %v", tree.TreeId, err)
   109  				return err
   110  			}
   111  			glog.Errorf("failed to InitMap(%+v): %T %v", req, err, err)
   112  			return err
   113  		}
   114  		glog.Infof("Initialised Map (%x) with new SignedMapRoot:\n%+v", tree.TreeId, resp.Created)
   115  
   116  		return nil
   117  	})
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	// Wait for map root to become available.
   123  	return b.Retry(ctx, func() error {
   124  		_, err := mapClient.GetSignedMapRootByRevision(ctx,
   125  			&trillian.GetSignedMapRootByRevisionRequest{
   126  				MapId:    tree.TreeId,
   127  				Revision: 0,
   128  			})
   129  		return err
   130  	})
   131  }
   132  
   133  // InitLog initialises a freshly created Log tree.
   134  func InitLog(ctx context.Context, tree *trillian.Tree, logClient trillian.TrillianLogClient) error {
   135  	if tree.TreeType != trillian.TreeType_LOG &&
   136  		tree.TreeType != trillian.TreeType_PREORDERED_LOG {
   137  		return fmt.Errorf("InitLog called with tree of type %v", tree.TreeType)
   138  	}
   139  
   140  	b := &backoff.Backoff{
   141  		Min:    100 * time.Millisecond,
   142  		Max:    10 * time.Second,
   143  		Factor: 2,
   144  		Jitter: true,
   145  	}
   146  
   147  	err := b.Retry(ctx, func() error {
   148  		glog.Infof("Initialising Log %x...", tree.TreeId)
   149  		req := &trillian.InitLogRequest{LogId: tree.TreeId}
   150  		resp, err := logClient.InitLog(ctx, req)
   151  		if err != nil {
   152  			switch s, ok := status.FromError(err); {
   153  			case ok && s.Code() == codes.Unavailable:
   154  				glog.Errorf("Log server unavailable: %v", err)
   155  				return err
   156  			case ok && s.Code() == codes.AlreadyExists:
   157  				glog.Warningf("Bizarrely, the just-created Log (%x) is already initialised!: %v", tree.TreeId, err)
   158  				return err
   159  			}
   160  			glog.Errorf("failed to InitLog(%+v): %T %v", req, err, err)
   161  			return err
   162  		}
   163  		glog.Infof("Initialised Log (%x) with new SignedTreeHead:\n%+v", tree.TreeId, resp.Created)
   164  
   165  		return nil
   166  	})
   167  	if err != nil {
   168  		return err
   169  	}
   170  
   171  	// Wait for log root to become available.
   172  	return b.Retry(ctx, func() error {
   173  		_, err := logClient.GetLatestSignedLogRoot(ctx,
   174  			&trillian.GetLatestSignedLogRootRequest{LogId: tree.TreeId})
   175  		return err
   176  	})
   177  }