github.com/letterj/go-ethereum@v1.8.22-0.20190204142846-520024dfd689/cmd/swarm/swarm-smoke/util.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/md5" 23 crand "crypto/rand" 24 "errors" 25 "fmt" 26 "io" 27 "io/ioutil" 28 "net/http" 29 "net/http/httptrace" 30 "os" 31 "time" 32 33 "github.com/ethereum/go-ethereum/log" 34 "github.com/ethereum/go-ethereum/metrics" 35 "github.com/ethereum/go-ethereum/swarm/api" 36 "github.com/ethereum/go-ethereum/swarm/api/client" 37 "github.com/ethereum/go-ethereum/swarm/spancontext" 38 opentracing "github.com/opentracing/opentracing-go" 39 cli "gopkg.in/urfave/cli.v1" 40 ) 41 42 var ( 43 commandName = "" 44 ) 45 46 func wrapCliCommand(name string, killOnTimeout bool, command func(*cli.Context) error) func(*cli.Context) error { 47 return func(ctx *cli.Context) error { 48 log.PrintOrigins(true) 49 log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(verbosity), log.StreamHandler(os.Stdout, log.TerminalFormat(false)))) 50 51 defer func(now time.Time) { 52 totalTime := time.Since(now) 53 log.Info("total time", "time", totalTime, "kb", filesize) 54 metrics.GetOrRegisterResettingTimer(name+".total-time", nil).Update(totalTime) 55 }(time.Now()) 56 57 log.Info("smoke test starting", "task", name, "timeout", timeout) 58 commandName = name 59 metrics.GetOrRegisterCounter(name, nil).Inc(1) 60 61 errc := make(chan error) 62 done := make(chan struct{}) 63 64 if killOnTimeout { 65 go func() { 66 <-time.After(time.Duration(timeout) * time.Second) 67 close(done) 68 }() 69 } 70 71 go func() { 72 errc <- command(ctx) 73 }() 74 75 select { 76 case err := <-errc: 77 if err != nil { 78 metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", name), nil).Inc(1) 79 } 80 return err 81 case <-done: 82 metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", name), nil).Inc(1) 83 return fmt.Errorf("timeout after %v sec", timeout) 84 } 85 } 86 } 87 88 func generateEndpoints(scheme string, cluster string, app string, from int, to int) { 89 if cluster == "prod" { 90 for port := from; port < to; port++ { 91 endpoints = append(endpoints, fmt.Sprintf("%s://%v.swarm-gateways.net", scheme, port)) 92 } 93 } else if cluster == "private-internal" { 94 for port := from; port < to; port++ { 95 endpoints = append(endpoints, fmt.Sprintf("%s://swarm-private-internal-%v:8500", scheme, port)) 96 } 97 } else { 98 for port := from; port < to; port++ { 99 endpoints = append(endpoints, fmt.Sprintf("%s://%s-%v-%s.stg.swarm-gateways.net", scheme, app, port, cluster)) 100 } 101 } 102 103 if includeLocalhost { 104 endpoints = append(endpoints, "http://localhost:8500") 105 } 106 } 107 108 //just use the first endpoint 109 func generateEndpoint(scheme string, cluster string, app string, from int) string { 110 if cluster == "prod" { 111 return fmt.Sprintf("%s://%v.swarm-gateways.net", scheme, from) 112 } else if cluster == "private-internal" { 113 return fmt.Sprintf("%s://swarm-private-internal-%v:8500", scheme, from) 114 } else { 115 return fmt.Sprintf("%s://%s-%v-%s.stg.swarm-gateways.net", scheme, app, from, cluster) 116 } 117 } 118 119 func fetchFeed(topic string, user string, endpoint string, original []byte, ruid string) error { 120 ctx, sp := spancontext.StartSpan(context.Background(), "feed-and-sync.fetch") 121 defer sp.Finish() 122 123 log.Trace("sleeping", "ruid", ruid) 124 time.Sleep(3 * time.Second) 125 126 log.Trace("http get request (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user) 127 128 var tn time.Time 129 reqUri := endpoint + "/bzz-feed:/?topic=" + topic + "&user=" + user 130 req, _ := http.NewRequest("GET", reqUri, nil) 131 132 opentracing.GlobalTracer().Inject( 133 sp.Context(), 134 opentracing.HTTPHeaders, 135 opentracing.HTTPHeadersCarrier(req.Header)) 136 137 trace := client.GetClientTrace("feed-and-sync - http get", "feed-and-sync", ruid, &tn) 138 139 req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) 140 transport := http.DefaultTransport 141 142 //transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} 143 144 tn = time.Now() 145 res, err := transport.RoundTrip(req) 146 if err != nil { 147 log.Error(err.Error(), "ruid", ruid) 148 return err 149 } 150 151 log.Trace("http get response (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user, "code", res.StatusCode, "len", res.ContentLength) 152 153 if res.StatusCode != 200 { 154 return fmt.Errorf("expected status code %d, got %v (ruid %v)", 200, res.StatusCode, ruid) 155 } 156 157 defer res.Body.Close() 158 159 rdigest, err := digest(res.Body) 160 if err != nil { 161 log.Warn(err.Error(), "ruid", ruid) 162 return err 163 } 164 165 if !bytes.Equal(rdigest, original) { 166 err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) 167 log.Warn(err.Error(), "ruid", ruid) 168 return err 169 } 170 171 log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) 172 173 return nil 174 } 175 176 // fetch is getting the requested `hash` from the `endpoint` and compares it with the `original` file 177 func fetch(hash string, endpoint string, original []byte, ruid string) error { 178 ctx, sp := spancontext.StartSpan(context.Background(), "upload-and-sync.fetch") 179 defer sp.Finish() 180 181 log.Trace("http get request", "ruid", ruid, "api", endpoint, "hash", hash) 182 183 var tn time.Time 184 reqUri := endpoint + "/bzz:/" + hash + "/" 185 req, _ := http.NewRequest("GET", reqUri, nil) 186 187 opentracing.GlobalTracer().Inject( 188 sp.Context(), 189 opentracing.HTTPHeaders, 190 opentracing.HTTPHeadersCarrier(req.Header)) 191 192 trace := client.GetClientTrace(commandName+" - http get", commandName, ruid, &tn) 193 194 req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) 195 transport := http.DefaultTransport 196 197 //transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} 198 199 tn = time.Now() 200 res, err := transport.RoundTrip(req) 201 if err != nil { 202 log.Error(err.Error(), "ruid", ruid) 203 return err 204 } 205 log.Trace("http get response", "ruid", ruid, "api", endpoint, "hash", hash, "code", res.StatusCode, "len", res.ContentLength) 206 207 if res.StatusCode != 200 { 208 err := fmt.Errorf("expected status code %d, got %v", 200, res.StatusCode) 209 log.Warn(err.Error(), "ruid", ruid) 210 return err 211 } 212 213 defer res.Body.Close() 214 215 rdigest, err := digest(res.Body) 216 if err != nil { 217 log.Warn(err.Error(), "ruid", ruid) 218 return err 219 } 220 221 if !bytes.Equal(rdigest, original) { 222 err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) 223 log.Warn(err.Error(), "ruid", ruid) 224 return err 225 } 226 227 log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) 228 229 return nil 230 } 231 232 // upload an arbitrary byte as a plaintext file to `endpoint` using the api client 233 func upload(r io.Reader, size int, endpoint string) (string, error) { 234 swarm := client.NewClient(endpoint) 235 f := &client.File{ 236 ReadCloser: ioutil.NopCloser(r), 237 ManifestEntry: api.ManifestEntry{ 238 ContentType: "text/plain", 239 Mode: 0660, 240 Size: int64(size), 241 }, 242 } 243 244 // upload data to bzz:// and retrieve the content-addressed manifest hash, hex-encoded. 245 return swarm.Upload(f, "", false) 246 } 247 248 func digest(r io.Reader) ([]byte, error) { 249 h := md5.New() 250 _, err := io.Copy(h, r) 251 if err != nil { 252 return nil, err 253 } 254 return h.Sum(nil), nil 255 } 256 257 // generates random data in heap buffer 258 func generateRandomData(datasize int) ([]byte, error) { 259 b := make([]byte, datasize) 260 c, err := crand.Read(b) 261 if err != nil { 262 return nil, err 263 } else if c != datasize { 264 return nil, errors.New("short read") 265 } 266 return b, nil 267 }