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 }