provider_schema.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. Copyright © 2025 ESO Maintainer Team
  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. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package v1
  14. import (
  15. "encoding/json"
  16. "errors"
  17. "fmt"
  18. "sync"
  19. )
  20. var builder map[string]Provider
  21. var buildlock sync.RWMutex
  22. func init() {
  23. builder = make(map[string]Provider)
  24. }
  25. // Register a store backend type. Register panics if a
  26. // backend with the same store is already registered.
  27. func Register(s Provider, storeSpec *SecretStoreProvider, maintenanceStatus MaintenanceStatus) {
  28. storeName, err := getProviderName(storeSpec)
  29. if err != nil {
  30. panic(fmt.Sprintf("store error registering schema: %s", err.Error()))
  31. }
  32. RegisterMaintenanceStatus(maintenanceStatus, storeSpec)
  33. buildlock.Lock()
  34. defer buildlock.Unlock()
  35. _, exists := builder[storeName]
  36. if exists {
  37. panic(fmt.Sprintf("store %q already registered", storeName))
  38. }
  39. builder[storeName] = s
  40. }
  41. // ForceRegister adds to store schema, overwriting a store if
  42. // already registered. Should only be used for testing.
  43. func ForceRegister(s Provider, storeSpec *SecretStoreProvider, maintenanceStatus MaintenanceStatus) {
  44. storeName, err := getProviderName(storeSpec)
  45. if err != nil {
  46. panic(fmt.Sprintf("store error registering schema: %s", err.Error()))
  47. }
  48. buildlock.Lock()
  49. builder[storeName] = s
  50. buildlock.Unlock()
  51. ForceRegisterMaintenanceStatus(maintenanceStatus, storeSpec)
  52. }
  53. // GetProviderByName returns the provider implementation by name.
  54. func GetProviderByName(name string) (Provider, bool) {
  55. buildlock.RLock()
  56. f, ok := builder[name]
  57. buildlock.RUnlock()
  58. return f, ok
  59. }
  60. // GetProvider returns the provider from the generic store.
  61. func GetProvider(s GenericStore) (Provider, error) {
  62. if s == nil {
  63. return nil, nil
  64. }
  65. spec := s.GetSpec()
  66. if spec == nil {
  67. // Note, this condition can never be reached, because
  68. // the Spec is not a pointer in Kubernetes. It will
  69. // always exist.
  70. return nil, fmt.Errorf("no spec found in %#v", s)
  71. }
  72. storeName, err := getProviderName(spec.Provider)
  73. if err != nil {
  74. return nil, fmt.Errorf("store error for %s: %w", s.GetName(), err)
  75. }
  76. buildlock.RLock()
  77. f, ok := builder[storeName]
  78. buildlock.RUnlock()
  79. if !ok {
  80. return nil, fmt.Errorf("failed to find registered store backend for type: %s, name: %s", storeName, s.GetName())
  81. }
  82. return f, nil
  83. }
  84. // getProviderName returns the name of the configured provider
  85. // or an error if the provider is not configured.
  86. func getProviderName(storeSpec *SecretStoreProvider) (string, error) {
  87. storeBytes, err := json.Marshal(storeSpec)
  88. if err != nil || storeBytes == nil {
  89. return "", fmt.Errorf("failed to marshal store spec: %w", err)
  90. }
  91. storeMap := make(map[string]any)
  92. err = json.Unmarshal(storeBytes, &storeMap)
  93. if err != nil {
  94. return "", fmt.Errorf("failed to unmarshal store spec: %w", err)
  95. }
  96. if len(storeMap) != 1 {
  97. return "", fmt.Errorf("secret stores must only have exactly one backend specified, found %d", len(storeMap))
  98. }
  99. for k := range storeMap {
  100. return k, nil
  101. }
  102. return "", errors.New("failed to find registered store backend")
  103. }