github.com/thanos-io/thanos@v0.32.5/test/e2e/tools_bucket_web_test.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package e2e_test 5 6 import ( 7 "context" 8 "encoding/json" 9 "io" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "path" 14 "path/filepath" 15 "testing" 16 "time" 17 18 "github.com/efficientgo/e2e" 19 e2edb "github.com/efficientgo/e2e/db" 20 "github.com/go-kit/log" 21 "github.com/prometheus/prometheus/model/labels" 22 "github.com/prometheus/prometheus/model/timestamp" 23 "github.com/thanos-io/objstore/providers/s3" 24 25 "github.com/thanos-io/objstore" 26 "github.com/thanos-io/objstore/client" 27 28 "github.com/efficientgo/core/testutil" 29 v1 "github.com/thanos-io/thanos/pkg/api/blocks" 30 "github.com/thanos-io/thanos/pkg/errors" 31 "github.com/thanos-io/thanos/pkg/runutil" 32 "github.com/thanos-io/thanos/test/e2e/e2ethanos" 33 ) 34 35 func TestToolsBucketWebExternalPrefixWithoutReverseProxy(t *testing.T) { 36 t.Parallel() 37 38 e, err := e2e.NewDockerEnvironment("route-prefix") 39 testutil.Ok(t, err) 40 t.Cleanup(e2ethanos.CleanScenario(t, e)) 41 42 externalPrefix := "testThanos" 43 44 const bucket = "compact-test" 45 m := e2edb.NewMinio(e, "thanos", bucket, e2edb.WithMinioTLS()) 46 testutil.Ok(t, e2e.StartAndWaitReady(m)) 47 48 svcConfig := client.BucketConfig{ 49 Type: client.S3, 50 Config: e2ethanos.NewS3Config(bucket, m.Endpoint("http"), m.InternalDir()), 51 } 52 53 b := e2ethanos.NewToolsBucketWeb( 54 e, 55 "1", 56 svcConfig, 57 "", 58 externalPrefix, 59 "", 60 "", 61 "", 62 ) 63 testutil.Ok(t, e2e.StartAndWaitReady(b)) 64 65 checkNetworkRequests(t, "http://"+b.Endpoint("http")+"/"+externalPrefix+"/blocks") 66 } 67 68 func TestToolsBucketWebExternalPrefix(t *testing.T) { 69 t.Parallel() 70 71 e, err := e2e.NewDockerEnvironment("external-prefix") 72 testutil.Ok(t, err) 73 t.Cleanup(e2ethanos.CleanScenario(t, e)) 74 75 externalPrefix := "testThanos" 76 const bucket = "toolsBucketWeb-test" 77 m := e2edb.NewMinio(e, "thanos", bucket, e2edb.WithMinioTLS()) 78 testutil.Ok(t, e2e.StartAndWaitReady(m)) 79 80 svcConfig := client.BucketConfig{ 81 Type: client.S3, 82 Config: e2ethanos.NewS3Config(bucket, m.Endpoint("http"), m.InternalDir()), 83 } 84 85 b := e2ethanos.NewToolsBucketWeb( 86 e, 87 "1", 88 svcConfig, 89 "", 90 externalPrefix, 91 "", 92 "", 93 "", 94 ) 95 testutil.Ok(t, e2e.StartAndWaitReady(b)) 96 97 toolsBucketWebURL := urlParse(t, "http://"+b.Endpoint("http")+"/"+externalPrefix) 98 99 toolsBucketWebProxy := httptest.NewServer(e2ethanos.NewSingleHostReverseProxy(toolsBucketWebURL, externalPrefix)) 100 t.Cleanup(toolsBucketWebProxy.Close) 101 102 checkNetworkRequests(t, toolsBucketWebProxy.URL+"/"+externalPrefix+"/blocks") 103 } 104 105 func TestToolsBucketWebExternalPrefixAndRoutePrefix(t *testing.T) { 106 t.Parallel() 107 108 e, err := e2e.NewDockerEnvironment("route-prefix") 109 testutil.Ok(t, err) 110 t.Cleanup(e2ethanos.CleanScenario(t, e)) 111 112 externalPrefix := "testThanos" 113 routePrefix := "test" 114 const bucket = "toolsBucketWeb-test" 115 m := e2edb.NewMinio(e, "thanos", bucket, e2edb.WithMinioTLS()) 116 testutil.Ok(t, err) 117 testutil.Ok(t, e2e.StartAndWaitReady(m)) 118 119 svcConfig := client.BucketConfig{ 120 Type: client.S3, 121 Config: e2ethanos.NewS3Config(bucket, m.Endpoint("http"), m.InternalDir()), 122 } 123 124 b := e2ethanos.NewToolsBucketWeb( 125 e, 126 "1", 127 svcConfig, 128 routePrefix, 129 externalPrefix, 130 "", 131 "", 132 "", 133 ) 134 testutil.Ok(t, e2e.StartAndWaitReady(b)) 135 136 toolsBucketWebURL := urlParse(t, "http://"+b.Endpoint("http")+"/"+routePrefix) 137 138 toolsBucketWebProxy := httptest.NewServer(e2ethanos.NewSingleHostReverseProxy(toolsBucketWebURL, externalPrefix)) 139 t.Cleanup(toolsBucketWebProxy.Close) 140 141 checkNetworkRequests(t, toolsBucketWebProxy.URL+"/"+externalPrefix+"/blocks") 142 } 143 144 func TestToolsBucketWebWithTimeAndRelabelFilter(t *testing.T) { 145 t.Parallel() 146 147 e, err := e2e.NewDockerEnvironment("time-relabel") 148 testutil.Ok(t, err) 149 t.Cleanup(e2ethanos.CleanScenario(t, e)) 150 151 // Create Minio. 152 const bucket = "toolsBucketWeb-test" 153 m := e2edb.NewMinio(e, "thanos", bucket, e2edb.WithMinioTLS()) 154 testutil.Ok(t, e2e.StartAndWaitReady(m)) 155 156 // Create bucket. 157 logger := log.NewLogfmtLogger(os.Stdout) 158 bkt, err := s3.NewBucketWithConfig(logger, 159 e2ethanos.NewS3Config(bucket, m.Endpoint("http"), m.Dir()), "tools") 160 testutil.Ok(t, err) 161 162 // Create share dir for upload. 163 dir := filepath.Join(e.SharedDir(), "tmp") 164 testutil.Ok(t, os.MkdirAll(dir, os.ModePerm)) 165 166 // Upload blocks. 167 now, err := time.Parse(time.RFC3339, "2021-07-24T08:00:00Z") 168 testutil.Ok(t, err) 169 blocks := []blockDesc{ 170 { 171 series: []labels.Labels{labels.FromStrings("a", "1", "b", "2")}, 172 extLset: labels.FromStrings("tenant_id", "b", "replica", "1"), 173 mint: timestamp.FromTime(now), 174 maxt: timestamp.FromTime(now.Add(2 * time.Hour)), 175 }, 176 { 177 series: []labels.Labels{labels.FromStrings("a", "1", "b", "2")}, 178 extLset: labels.FromStrings("tenant_id", "a", "replica", "1"), 179 mint: timestamp.FromTime(now), 180 maxt: timestamp.FromTime(now.Add(2 * time.Hour)), 181 }, 182 { 183 series: []labels.Labels{labels.FromStrings("a", "1", "b", "2")}, 184 extLset: labels.FromStrings("tenant_id", "b", "replica", "1"), 185 mint: timestamp.FromTime(now.Add(2 * time.Hour)), 186 maxt: timestamp.FromTime(now.Add(4 * time.Hour)), 187 }, 188 } 189 for _, b := range blocks { 190 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 191 t.Cleanup(cancel) 192 193 id, err := b.Create(ctx, dir, 0, b.hashFunc, 120) 194 testutil.Ok(t, err) 195 testutil.Ok(t, runutil.Retry(time.Second, ctx.Done(), func() error { 196 return objstore.UploadDir(ctx, logger, bkt, path.Join(dir, id.String()), id.String()) 197 })) 198 } 199 // Start thanos tool bucket web. 200 svcConfig := client.BucketConfig{ 201 Type: client.S3, 202 Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("http"), m.InternalDir()), 203 } 204 b := e2ethanos.NewToolsBucketWeb( 205 e, 206 "1", 207 svcConfig, 208 "", 209 "", 210 now.Format(time.RFC3339), 211 now.Add(1*time.Hour).Format(time.RFC3339), 212 ` 213 - action: keep 214 regex: "b" 215 source_labels: ["tenant_id"]`, 216 ) 217 testutil.Ok(t, e2e.StartAndWaitReady(b)) 218 219 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) 220 t.Cleanup(cancel) 221 222 var respData struct { 223 Status string 224 Data *v1.BlocksInfo 225 } 226 227 testutil.Ok(t, runutil.Retry(5*time.Second, ctx.Done(), func() error { 228 // Request blocks api. 229 resp, err := http.DefaultClient.Get("http://" + b.Endpoint("http") + "/api/v1/blocks") 230 if err != nil { 231 return err 232 } 233 234 if resp.StatusCode != http.StatusOK { 235 return errors.Newf("statuscode is not 200, got %d", resp.StatusCode) 236 } 237 238 body, err := io.ReadAll(resp.Body) 239 if err != nil { 240 return errors.Wrapf(err, "error reading body") 241 } 242 243 if err := resp.Body.Close(); err != nil { 244 return errors.Wrapf(err, "error closing body") 245 } 246 247 if err := json.Unmarshal(body, &respData); err != nil { 248 return errors.Wrapf(err, "error unmarshaling body") 249 } 250 251 if respData.Status != "success" { 252 return errors.Newf("status is not success, got %s", respData.Status) 253 } 254 255 // Filtered by time and relabel, result only one blocks. 256 if len(respData.Data.Blocks) == 1 { 257 return nil 258 } 259 260 return errors.Newf("expected 1 block, got %d", len(respData.Data.Blocks)) 261 })) 262 263 testutil.Equals(t, 1, len(respData.Data.Blocks)) 264 testutil.Equals(t, respData.Data.Blocks[0].MaxTime, blocks[0].maxt) 265 testutil.Equals(t, respData.Data.Blocks[0].MinTime, blocks[0].mint) 266 testutil.Equals(t, respData.Data.Blocks[0].Thanos.Labels, blocks[0].extLset.Map()) 267 }