client.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. Copyright © The ESO Authors
  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 generator adapts v1 generator implementations to the v2 gRPC GeneratorProvider interface.
  14. package generator
  15. import (
  16. "context"
  17. "encoding/json"
  18. "fmt"
  19. apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  20. "sigs.k8s.io/controller-runtime/pkg/client"
  21. genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
  22. genpb "github.com/external-secrets/external-secrets/proto/generator"
  23. )
  24. // Client wraps a v2 gRPC generator client and implements the v1 Generator interface.
  25. // This allows v2 generators to be used with the existing generator infrastructure.
  26. type Client struct {
  27. client genpb.GeneratorProviderClient
  28. generatorRef *genpb.GeneratorRef
  29. sourceNamespace string
  30. }
  31. // Ensure Client implements Generator interface.
  32. var _ genv1alpha1.Generator = &Client{}
  33. // NewClient creates a new wrapper that adapts a v2 gRPC generator to v1 Generator interface.
  34. func NewClient(client genpb.GeneratorProviderClient, generatorRef *genpb.GeneratorRef, sourceNamespace string) genv1alpha1.Generator {
  35. return &Client{
  36. client: client,
  37. generatorRef: generatorRef,
  38. sourceNamespace: sourceNamespace,
  39. }
  40. }
  41. // Generate creates a new secret or set of secrets using the v2 gRPC generator.
  42. // The jsonSpec parameter is ignored since the generator reference is already stored.
  43. func (w *Client) Generate(ctx context.Context, jsonSpec *apiextensions.JSON, _ client.Client, namespace string) (map[string][]byte, genv1alpha1.GeneratorProviderState, error) {
  44. // If jsonSpec is provided, we need to extract the generator reference from it
  45. // However, for v2 generators, we already have the reference, so we can use that
  46. // But we should validate that the jsonSpec matches our stored reference if provided
  47. if jsonSpec != nil {
  48. // Parse the jsonSpec to extract metadata if needed
  49. var meta struct {
  50. Metadata struct {
  51. Name string `json:"name"`
  52. Namespace string `json:"namespace"`
  53. } `json:"metadata"`
  54. APIVersion string `json:"apiVersion"`
  55. Kind string `json:"kind"`
  56. }
  57. if err := json.Unmarshal(jsonSpec.Raw, &meta); err == nil {
  58. // Update the generator ref with the actual resource info
  59. if meta.Metadata.Name != "" {
  60. w.generatorRef.Name = meta.Metadata.Name
  61. }
  62. if meta.Metadata.Namespace != "" {
  63. w.generatorRef.Namespace = meta.Metadata.Namespace
  64. }
  65. if meta.APIVersion != "" {
  66. w.generatorRef.ApiVersion = meta.APIVersion
  67. }
  68. if meta.Kind != "" {
  69. w.generatorRef.Kind = meta.Kind
  70. }
  71. }
  72. }
  73. // Use the provided namespace as the source namespace
  74. sourceNs := namespace
  75. if sourceNs == "" {
  76. sourceNs = w.sourceNamespace
  77. }
  78. // Call the v2 gRPC Generate
  79. resp, err := w.client.Generate(ctx, &genpb.GenerateRequest{
  80. GeneratorRef: w.generatorRef,
  81. SourceNamespace: sourceNs,
  82. })
  83. if err != nil {
  84. return nil, nil, fmt.Errorf("failed to call v2 generator: %w", err)
  85. }
  86. // Convert state bytes to GeneratorProviderState
  87. var state genv1alpha1.GeneratorProviderState
  88. if len(resp.State) > 0 {
  89. state = &apiextensions.JSON{Raw: resp.State}
  90. }
  91. return resp.Secrets, state, nil
  92. }
  93. // Cleanup deletes any resources created during the Generate phase.
  94. func (w *Client) Cleanup(ctx context.Context, _ *apiextensions.JSON, state genv1alpha1.GeneratorProviderState, _ client.Client, namespace string) error {
  95. // Extract state bytes
  96. var stateBytes []byte
  97. if state != nil {
  98. stateBytes = state.Raw
  99. }
  100. // Use the provided namespace as the source namespace
  101. sourceNs := namespace
  102. if sourceNs == "" {
  103. sourceNs = w.sourceNamespace
  104. }
  105. // Call the v2 gRPC Cleanup
  106. _, err := w.client.Cleanup(ctx, &genpb.CleanupRequest{
  107. GeneratorRef: w.generatorRef,
  108. State: stateBytes,
  109. SourceNamespace: sourceNs,
  110. })
  111. if err != nil {
  112. return fmt.Errorf("failed to call v2 generator cleanup: %w", err)
  113. }
  114. return nil
  115. }