github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/ctl/service/r2/store/stub/store.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE 20 21 package stub 22 23 import ( 24 "errors" 25 "fmt" 26 "time" 27 28 "github.com/m3db/m3/src/ctl/service/r2" 29 r2store "github.com/m3db/m3/src/ctl/service/r2/store" 30 "github.com/m3db/m3/src/metrics/aggregation" 31 "github.com/m3db/m3/src/metrics/pipeline" 32 "github.com/m3db/m3/src/metrics/policy" 33 "github.com/m3db/m3/src/metrics/rules/view" 34 "github.com/m3db/m3/src/metrics/rules/view/changes" 35 "github.com/m3db/m3/src/metrics/x/bytes" 36 "github.com/m3db/m3/src/x/instrument" 37 38 "github.com/pborman/uuid" 39 ) 40 41 type mappingRuleHistories map[string][]view.MappingRule 42 type rollupRuleHistories map[string][]view.RollupRule 43 44 type stubData struct { 45 Namespaces view.Namespaces 46 ErrorNamespace string 47 ConflictNamespace string 48 RuleSets map[string]view.RuleSet 49 MappingHistory map[string]mappingRuleHistories 50 RollupHistory map[string]rollupRuleHistories 51 } 52 53 var ( 54 errNotImplemented = errors.New("not implemented") 55 cutoverMillis = time.Now().UnixNano() / int64(time.Millisecond/time.Nanosecond) 56 ) 57 58 // Operator contains the data necessary to implement stubbed out implementations for various r2 operations. 59 type store struct { 60 data *stubData 61 iOpts instrument.Options 62 } 63 64 // NewStore creates a new stub 65 func NewStore(iOpts instrument.Options) (r2store.Store, error) { 66 dummyData, err := buildDummyData() 67 if err != nil { 68 return nil, err 69 } 70 71 return &store{data: &dummyData, iOpts: iOpts}, err 72 } 73 74 func buildDummyData() (stubData, error) { 75 rollup1, err := pipeline.NewRollupOp( 76 pipeline.GroupByRollupType, 77 "testTarget", 78 []string{"tag1", "tag2"}, 79 aggregation.MustCompressTypes(aggregation.Min), 80 ) 81 if err != nil { 82 return stubData{}, err 83 } 84 rollup2, err := pipeline.NewRollupOp( 85 pipeline.GroupByRollupType, 86 "testTarget", 87 []string{"tag1", "tag2"}, 88 aggregation.MustCompressTypes(aggregation.Min), 89 ) 90 if err != nil { 91 return stubData{}, err 92 } 93 rollup3, err := pipeline.NewRollupOp( 94 pipeline.GroupByRollupType, 95 "testTarget", 96 []string{"tag1", "tag2"}, 97 aggregation.MustCompressTypes(aggregation.Min, aggregation.Max), 98 ) 99 if err != nil { 100 return stubData{}, err 101 } 102 rollup4, err := pipeline.NewRollupOp( 103 pipeline.GroupByRollupType, 104 "testTarget", 105 []string{"tag1", "tag2"}, 106 aggregation.MustCompressTypes(aggregation.P999), 107 ) 108 if err != nil { 109 return stubData{}, err 110 } 111 rollup5, err := pipeline.NewRollupOp( 112 pipeline.GroupByRollupType, 113 "testTarget", 114 []string{"tag1", "tag2"}, 115 aggregation.MustCompressTypes(aggregation.Min, aggregation.Max), 116 ) 117 if err != nil { 118 return stubData{}, err 119 } 120 rollup6, err := pipeline.NewRollupOp( 121 pipeline.GroupByRollupType, 122 "testTarget", 123 []string{"tag1", "tag2"}, 124 aggregation.MustCompressTypes(aggregation.P999), 125 ) 126 if err != nil { 127 return stubData{}, err 128 } 129 rollup7, err := pipeline.NewRollupOp( 130 pipeline.GroupByRollupType, 131 "testTarget", 132 []string{"tag1", "tag2"}, 133 aggregation.MustCompressTypes(aggregation.Min, aggregation.Max), 134 ) 135 if err != nil { 136 return stubData{}, err 137 } 138 rollup8, err := pipeline.NewRollupOp( 139 pipeline.GroupByRollupType, 140 "testTarget", 141 []string{"tag1", "tag2"}, 142 aggregation.MustCompressTypes(aggregation.Min, aggregation.Max), 143 ) 144 if err != nil { 145 return stubData{}, err 146 } 147 rollup9, err := pipeline.NewRollupOp( 148 pipeline.GroupByRollupType, 149 "testTarget", 150 []string{"tag1", "tag2"}, 151 aggregation.MustCompressTypes(aggregation.P999), 152 ) 153 if err != nil { 154 return stubData{}, err 155 } 156 return stubData{ 157 ErrorNamespace: "errNs", 158 ConflictNamespace: "conflictNs", 159 Namespaces: view.Namespaces{ 160 Version: 1, 161 Namespaces: []view.Namespace{ 162 { 163 ID: "ns1", 164 ForRuleSetVersion: 1, 165 Tombstoned: false, 166 }, 167 { 168 ID: "ns2", 169 ForRuleSetVersion: 1, 170 Tombstoned: false, 171 }, 172 }, 173 }, 174 RuleSets: map[string]view.RuleSet{ 175 "ns1": { 176 Namespace: "ns1", 177 Version: 1, 178 CutoverMillis: cutoverMillis, 179 MappingRules: []view.MappingRule{ 180 { 181 ID: "mr_id1", 182 Name: "mr1", 183 CutoverMillis: cutoverMillis, 184 Filter: "tag1:val1 tag2:val2", 185 StoragePolicies: policy.StoragePolicies{ 186 policy.MustParseStoragePolicy("1m:10d"), 187 policy.MustParseStoragePolicy("10m:30d"), 188 }, 189 }, 190 { 191 ID: "mr_id2", 192 Name: "mr2", 193 CutoverMillis: cutoverMillis, 194 Filter: "tag2:val2", 195 StoragePolicies: policy.StoragePolicies{ 196 policy.MustParseStoragePolicy("1m:10d"), 197 }, 198 }, 199 }, 200 RollupRules: []view.RollupRule{ 201 { 202 ID: "rr_id1", 203 Name: "rr1", 204 CutoverMillis: cutoverMillis, 205 Filter: "tag1:val1 tag2:val2", 206 Targets: []view.RollupTarget{ 207 { 208 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 209 { 210 Type: pipeline.RollupOpType, 211 Rollup: rollup1, 212 }, 213 }), 214 StoragePolicies: policy.StoragePolicies{ 215 policy.MustParseStoragePolicy("1m:10d"), 216 }, 217 }, 218 }, 219 }, 220 { 221 ID: "rr_id2", 222 Name: "rr2", 223 CutoverMillis: cutoverMillis, 224 Filter: "tag1:val1", 225 Targets: []view.RollupTarget{ 226 { 227 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 228 { 229 Type: pipeline.RollupOpType, 230 Rollup: rollup2, 231 }, 232 }), 233 StoragePolicies: policy.StoragePolicies{ 234 policy.MustParseStoragePolicy("1m:30d"), 235 }, 236 }, 237 }, 238 }, 239 }, 240 }, 241 "ns2": { 242 Namespace: "ns2", 243 Version: 1, 244 CutoverMillis: cutoverMillis, 245 MappingRules: []view.MappingRule{}, 246 RollupRules: []view.RollupRule{ 247 { 248 ID: "rr_id3", 249 Name: "rr1", 250 CutoverMillis: cutoverMillis, 251 Filter: "tag1:val1 tag2:val2", 252 Targets: []view.RollupTarget{ 253 { 254 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 255 { 256 Type: pipeline.RollupOpType, 257 Rollup: rollup3, 258 }, 259 }), 260 StoragePolicies: policy.StoragePolicies{ 261 policy.MustParseStoragePolicy("1m:10d"), 262 }, 263 }, 264 { 265 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 266 { 267 Type: pipeline.RollupOpType, 268 Rollup: rollup4, 269 }, 270 }), 271 StoragePolicies: policy.StoragePolicies{ 272 policy.MustParseStoragePolicy("1m:10d"), 273 }, 274 }, 275 }, 276 }, 277 }, 278 }, 279 }, 280 MappingHistory: map[string]mappingRuleHistories{ 281 "ns1": { 282 "mr_id1": []view.MappingRule{ 283 { 284 ID: "mr_id1", 285 Name: "mr1", 286 CutoverMillis: cutoverMillis, 287 Filter: "tag1:val1 tag2:val2", 288 StoragePolicies: policy.StoragePolicies{ 289 policy.MustParseStoragePolicy("1m:10d"), 290 policy.MustParseStoragePolicy("10m:30d"), 291 }, 292 }, 293 }, 294 "mr_id2": []view.MappingRule{ 295 { 296 ID: "mr_id2", 297 Name: "mr2", 298 CutoverMillis: cutoverMillis, 299 Filter: "tag1:val1 tag2:val2", 300 StoragePolicies: policy.StoragePolicies{ 301 policy.MustParseStoragePolicy("1m:10d"), 302 policy.MustParseStoragePolicy("10m:30d"), 303 }, 304 }, 305 }, 306 }, 307 "ns2": nil, 308 }, 309 RollupHistory: map[string]rollupRuleHistories{ 310 "ns1": { 311 "rr_id1": []view.RollupRule{ 312 { 313 ID: "rr_id1", 314 Name: "rr1", 315 CutoverMillis: cutoverMillis, 316 Filter: "tag1:val1 tag2:val2", 317 Targets: []view.RollupTarget{ 318 { 319 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 320 { 321 Type: pipeline.RollupOpType, 322 Rollup: rollup5, 323 }, 324 }), 325 StoragePolicies: policy.StoragePolicies{ 326 policy.MustParseStoragePolicy("1m:10d"), 327 }, 328 }, 329 { 330 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 331 { 332 Type: pipeline.RollupOpType, 333 Rollup: rollup6, 334 }, 335 }), 336 StoragePolicies: policy.StoragePolicies{ 337 policy.MustParseStoragePolicy("1m:10d"), 338 }, 339 }, 340 }, 341 }, 342 { 343 ID: "rr_id1", 344 Name: "rr1", 345 CutoverMillis: cutoverMillis, 346 Filter: "tag1:val1", 347 Targets: []view.RollupTarget{ 348 { 349 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 350 { 351 Type: pipeline.RollupOpType, 352 Rollup: rollup7, 353 }, 354 }), 355 StoragePolicies: policy.StoragePolicies{ 356 policy.MustParseStoragePolicy("1m:10d"), 357 }, 358 }, 359 }, 360 }, 361 }, 362 }, 363 "ns2": { 364 "rr_id3": []view.RollupRule{ 365 { 366 ID: "rr_id1", 367 Name: "rr1", 368 CutoverMillis: cutoverMillis, 369 Filter: "tag1:val1 tag2:val2", 370 Targets: []view.RollupTarget{ 371 { 372 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 373 { 374 Type: pipeline.RollupOpType, 375 Rollup: rollup8, 376 }, 377 }), 378 StoragePolicies: policy.StoragePolicies{ 379 policy.MustParseStoragePolicy("1m:10d"), 380 }, 381 }, 382 { 383 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 384 { 385 Type: pipeline.RollupOpType, 386 Rollup: rollup9, 387 }, 388 }), 389 StoragePolicies: policy.StoragePolicies{ 390 policy.MustParseStoragePolicy("1m:10d"), 391 }, 392 }, 393 }, 394 }, 395 }, 396 }, 397 }, 398 }, nil 399 } 400 401 func (s *store) FetchNamespaces() (view.Namespaces, error) { 402 return s.data.Namespaces, nil 403 } 404 405 func (s *store) CreateNamespace( 406 namespaceID string, 407 uOpts r2store.UpdateOptions, 408 ) (view.Namespace, error) { 409 switch namespaceID { 410 case s.data.ErrorNamespace: 411 return view.Namespace{}, r2.NewInternalError(fmt.Sprintf("could not create namespace: %s", namespaceID)) 412 case s.data.ConflictNamespace: 413 return view.Namespace{}, r2.NewVersionError(fmt.Sprintf("namespaces version mismatch")) 414 default: 415 for _, n := range s.data.Namespaces.Namespaces { 416 if namespaceID == n.ID { 417 return view.Namespace{}, r2.NewConflictError(fmt.Sprintf("namespace %s already exists", namespaceID)) 418 } 419 } 420 421 newView := view.Namespace{ 422 ID: namespaceID, 423 ForRuleSetVersion: 1, 424 } 425 426 s.data.Namespaces.Namespaces = append(s.data.Namespaces.Namespaces, newView) 427 s.data.RuleSets[namespaceID] = view.RuleSet{ 428 Namespace: namespaceID, 429 Version: 1, 430 CutoverMillis: time.Now().UnixNano(), 431 } 432 return newView, nil 433 } 434 } 435 436 func (s *store) ValidateRuleSet(rs view.RuleSet) error { 437 // Assumes no validation config for stub store so all rule sets are valid. 438 return nil 439 } 440 441 // This function is not supported. Use mocks package. 442 func (s *store) UpdateRuleSet( 443 rsChanges changes.RuleSetChanges, 444 version int, 445 uOpts r2store.UpdateOptions, 446 ) (view.RuleSet, error) { 447 return view.RuleSet{}, errNotImplemented 448 } 449 450 func (s *store) DeleteNamespace(namespaceID string, uOpts r2store.UpdateOptions) error { 451 switch namespaceID { 452 case s.data.ErrorNamespace: 453 return r2.NewInternalError("could not delete namespace") 454 case s.data.ConflictNamespace: 455 return r2.NewVersionError("namespace version mismatch") 456 default: 457 for i, n := range s.data.Namespaces.Namespaces { 458 if namespaceID == n.ID { 459 s.data.Namespaces.Namespaces = append(s.data.Namespaces.Namespaces[:i], s.data.Namespaces.Namespaces[i+1:]...) 460 return nil 461 } 462 } 463 return r2.NewConflictError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 464 } 465 } 466 467 func (s *store) FetchRuleSetSnapshot(namespaceID string) (view.RuleSet, error) { 468 switch namespaceID { 469 case s.data.ErrorNamespace: 470 return view.RuleSet{}, r2.NewInternalError(fmt.Sprintf("could not fetch namespace: %s", namespaceID)) 471 default: 472 for _, n := range s.data.Namespaces.Namespaces { 473 if namespaceID == n.ID { 474 rs := s.data.RuleSets[namespaceID] 475 return rs, nil 476 } 477 } 478 return view.RuleSet{}, r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 479 } 480 } 481 482 func (s *store) FetchMappingRule(namespaceID string, mappingRuleID string) (view.MappingRule, error) { 483 switch namespaceID { 484 case s.data.ErrorNamespace: 485 return view.MappingRule{}, r2.NewInternalError(fmt.Sprintf("could not fetch mappingRule: %s in namespace: %s", namespaceID, mappingRuleID)) 486 default: 487 rs, exists := s.data.RuleSets[namespaceID] 488 if !exists { 489 return view.MappingRule{}, r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 490 } 491 for _, m := range rs.MappingRules { 492 if mappingRuleID == m.ID { 493 return m, nil 494 } 495 } 496 return view.MappingRule{}, r2.NewNotFoundError(fmt.Sprintf("mappingRule: %s doesn't exist in Namespace: %s", mappingRuleID, namespaceID)) 497 } 498 } 499 500 func (s *store) CreateMappingRule( 501 namespaceID string, 502 mrv view.MappingRule, 503 uOpts r2store.UpdateOptions, 504 ) (view.MappingRule, error) { 505 switch namespaceID { 506 case s.data.ErrorNamespace: 507 return view.MappingRule{}, r2.NewInternalError("could not create mapping rule") 508 case s.data.ConflictNamespace: 509 return view.MappingRule{}, r2.NewVersionError("namespaces version mismatch") 510 default: 511 rs, exists := s.data.RuleSets[namespaceID] 512 if !exists { 513 return view.MappingRule{}, r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 514 } 515 516 for _, m := range rs.MappingRules { 517 if mrv.Name == m.Name { 518 return view.MappingRule{}, r2.NewConflictError(fmt.Sprintf("mapping rule: %s already exists in namespace: %s", mrv.Name, namespaceID)) 519 } 520 } 521 newID := uuid.New() 522 newRule := view.MappingRule{ 523 ID: newID, 524 Name: mrv.Name, 525 CutoverMillis: time.Now().UnixNano(), 526 Filter: mrv.Filter, 527 AggregationID: mrv.AggregationID, 528 StoragePolicies: mrv.StoragePolicies, 529 } 530 rs.MappingRules = append(rs.MappingRules, newRule) 531 return newRule, nil 532 } 533 } 534 535 func (s *store) UpdateMappingRule( 536 namespaceID, 537 mappingRuleID string, 538 mrv view.MappingRule, 539 uOpts r2store.UpdateOptions, 540 ) (view.MappingRule, error) { 541 switch namespaceID { 542 case s.data.ErrorNamespace: 543 return view.MappingRule{}, r2.NewInternalError("could not update mapping rule.") 544 case s.data.ConflictNamespace: 545 return view.MappingRule{}, r2.NewVersionError("namespaces version mismatch") 546 default: 547 rs, exists := s.data.RuleSets[namespaceID] 548 if !exists { 549 return view.MappingRule{}, r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 550 } 551 552 for i, m := range rs.MappingRules { 553 if mappingRuleID == m.ID { 554 newRule := view.MappingRule{ 555 ID: "new", 556 Name: mrv.Name, 557 CutoverMillis: time.Now().UnixNano(), 558 Filter: mrv.Filter, 559 AggregationID: mrv.AggregationID, 560 StoragePolicies: mrv.StoragePolicies, 561 } 562 rs.MappingRules[i] = newRule 563 return newRule, nil 564 } 565 } 566 return view.MappingRule{}, r2.NewNotFoundError(fmt.Sprintf("mapping rule: %s doesn't exist in namespace: %s", mappingRuleID, namespaceID)) 567 } 568 } 569 570 func (s *store) DeleteMappingRule( 571 namespaceID, 572 mappingRuleID string, 573 uOpts r2store.UpdateOptions, 574 ) error { 575 switch namespaceID { 576 case s.data.ErrorNamespace: 577 return r2.NewInternalError("could not delete mapping rule.") 578 case s.data.ConflictNamespace: 579 return r2.NewVersionError("namespaces version mismatch") 580 default: 581 rs, exists := s.data.RuleSets[namespaceID] 582 if !exists { 583 return r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 584 } 585 foundIdx := -1 586 for i, rule := range rs.MappingRules { 587 if rule.ID == mappingRuleID { 588 foundIdx = i 589 break 590 } 591 } 592 if foundIdx == -1 { 593 return r2.NewNotFoundError(fmt.Sprintf("mapping rule: %s doesn't exist in namespace: %s", mappingRuleID, namespaceID)) 594 } 595 rs.MappingRules = append(rs.MappingRules[:foundIdx], rs.MappingRules[foundIdx+1:]...) 596 return nil 597 } 598 } 599 600 func (s *store) FetchMappingRuleHistory(namespaceID, mappingRuleID string) ([]view.MappingRule, error) { 601 switch namespaceID { 602 case s.data.ErrorNamespace: 603 return nil, r2.NewInternalError(fmt.Sprintf("Could not fetch mappingRuleID: %s in namespace: %s", namespaceID, mappingRuleID)) 604 default: 605 ns, exists := s.data.MappingHistory[namespaceID] 606 if !exists { 607 return nil, r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 608 } 609 hist, exists := ns[mappingRuleID] 610 if !exists { 611 return nil, r2.NewNotFoundError(fmt.Sprintf("mappingRule: %s doesn't exist in Namespace: %s", mappingRuleID, namespaceID)) 612 } 613 return hist, nil 614 } 615 } 616 617 func (s *store) FetchRollupRule(namespaceID, rollupRuleID string) (view.RollupRule, error) { 618 switch namespaceID { 619 case s.data.ErrorNamespace: 620 return view.RollupRule{}, r2.NewInternalError(fmt.Sprintf("Could not fetch rollupRule: %s in namespace: %s", namespaceID, rollupRuleID)) 621 default: 622 rs, exists := s.data.RuleSets[namespaceID] 623 if !exists { 624 return view.RollupRule{}, r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 625 } 626 for _, r := range rs.RollupRules { 627 if rollupRuleID == r.ID { 628 return r, nil 629 } 630 } 631 return view.RollupRule{}, r2.NewNotFoundError(fmt.Sprintf("rollupRule: %s doesn't exist in Namespace: %s", rollupRuleID, namespaceID)) 632 } 633 } 634 635 func (s *store) CreateRollupRule( 636 namespaceID string, 637 rrv view.RollupRule, 638 uOpts r2store.UpdateOptions, 639 ) (view.RollupRule, error) { 640 switch namespaceID { 641 case s.data.ErrorNamespace: 642 return view.RollupRule{}, r2.NewInternalError("could not create rollup rule") 643 case s.data.ConflictNamespace: 644 return view.RollupRule{}, r2.NewVersionError("namespaces version mismatch") 645 default: 646 rs, exists := s.data.RuleSets[namespaceID] 647 if !exists { 648 return view.RollupRule{}, r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 649 } 650 for _, r := range rs.RollupRules { 651 if rrv.Name == r.Name { 652 return view.RollupRule{}, r2.NewConflictError(fmt.Sprintf("rollup rule: %s already exists in namespace: %s", rrv.Name, namespaceID)) 653 } 654 } 655 newID := uuid.New() 656 newRule := view.RollupRule{ 657 ID: newID, 658 Name: rrv.Name, 659 CutoverMillis: time.Now().UnixNano(), 660 Filter: rrv.Filter, 661 Targets: rrv.Targets, 662 } 663 rs.RollupRules = append(rs.RollupRules, newRule) 664 return newRule, nil 665 } 666 } 667 668 func (s *store) UpdateRollupRule( 669 namespaceID, 670 rollupRuleID string, 671 rrv view.RollupRule, 672 uOpts r2store.UpdateOptions, 673 ) (view.RollupRule, error) { 674 switch namespaceID { 675 case s.data.ErrorNamespace: 676 return view.RollupRule{}, r2.NewInternalError("could not update rollup rule.") 677 case s.data.ConflictNamespace: 678 return view.RollupRule{}, r2.NewVersionError("namespaces version mismatch") 679 default: 680 rs, exists := s.data.RuleSets[namespaceID] 681 if !exists { 682 return view.RollupRule{}, r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 683 } 684 685 for i, m := range rs.RollupRules { 686 if rollupRuleID == m.ID { 687 newRule := view.RollupRule{ 688 ID: rollupRuleID, 689 Name: rrv.Name, 690 CutoverMillis: time.Now().UnixNano(), 691 Filter: rrv.Filter, 692 Targets: rrv.Targets, 693 } 694 rs.RollupRules[i] = newRule 695 return newRule, nil 696 } 697 } 698 return view.RollupRule{}, r2.NewNotFoundError(fmt.Sprintf("rollup rule: %s doesn't exist in namespace: %s", rollupRuleID, namespaceID)) 699 } 700 } 701 702 func (s *store) DeleteRollupRule( 703 namespaceID, 704 rollupRuleID string, 705 uOpts r2store.UpdateOptions, 706 ) error { 707 switch namespaceID { 708 case s.data.ErrorNamespace: 709 return r2.NewInternalError("could not delete rollup rule.") 710 case s.data.ConflictNamespace: 711 return r2.NewVersionError("namespaces version mismatch") 712 default: 713 rs, exists := s.data.RuleSets[namespaceID] 714 if !exists { 715 return r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 716 } 717 718 foundIdx := -1 719 for i, rule := range rs.RollupRules { 720 if rule.ID == rollupRuleID { 721 foundIdx = i 722 break 723 } 724 } 725 if foundIdx == -1 { 726 return r2.NewNotFoundError(fmt.Sprintf("rollup rule: %s doesn't exist in namespace: %s", rollupRuleID, namespaceID)) 727 } 728 rs.RollupRules = append(rs.RollupRules[:foundIdx], rs.RollupRules[foundIdx+1:]...) 729 return nil 730 } 731 } 732 733 func (s *store) FetchRollupRuleHistory(namespaceID, rollupRuleID string) ([]view.RollupRule, error) { 734 switch namespaceID { 735 case s.data.ErrorNamespace: 736 return nil, r2.NewInternalError(fmt.Sprintf("Could not fetch rollupRule: %s in namespace: %s", namespaceID, rollupRuleID)) 737 default: 738 ns, exists := s.data.RollupHistory[namespaceID] 739 if !exists { 740 return nil, r2.NewNotFoundError(fmt.Sprintf("namespace %s doesn't exist", namespaceID)) 741 } 742 hist, exists := ns[rollupRuleID] 743 if !exists { 744 return nil, r2.NewNotFoundError(fmt.Sprintf("rollupRule: %s doesn't exist in Namespace: %s", rollupRuleID, namespaceID)) 745 } 746 return hist, nil 747 } 748 } 749 750 func (s *store) Close() {} 751 752 // nolint: unparam 753 func b(str string) []byte { return []byte(str) } 754 func bs(strs ...string) [][]byte { return bytes.ArraysFromStringArray(strs) }