client.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. // Package generator adapts v1 generator implementations to the v2 gRPC GeneratorProvider interface.
  13. package generator
  14. import (
  15. "context"
  16. "encoding/json"
  17. "fmt"
  18. apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  19. "sigs.k8s.io/controller-runtime/pkg/client"
  20. genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
  21. genpb "github.com/external-secrets/external-secrets/proto/generator"
  22. )
  23. // Client wraps a v2 gRPC generator client and implements the v1 Generator interface.
  24. // This allows v2 generators to be used with the existing generator infrastructure.
  25. type Client struct {
  26. client genpb.GeneratorProviderClient
  27. generatorRef *genpb.GeneratorRef
  28. sourceNamespace string
  29. }
  30. // Ensure Client implements Generator interface.
  31. var _ genv1alpha1.Generator = &Client{}
  32. // NewClient creates a new wrapper that adapts a v2 gRPC generator to v1 Generator interface.
  33. func NewClient(client genpb.GeneratorProviderClient, generatorRef *genpb.GeneratorRef, sourceNamespace string) genv1alpha1.Generator {
  34. return &Client{
  35. client: client,
  36. generatorRef: generatorRef,
  37. sourceNamespace: sourceNamespace,
  38. }
  39. }
  40. // Generate creates a new secret or set of secrets using the v2 gRPC generator.
  41. // The jsonSpec parameter is ignored since the generator reference is already stored.
  42. func (w *Client) Generate(ctx context.Context, jsonSpec *apiextensions.JSON, _ client.Client, namespace string) (map[string][]byte, genv1alpha1.GeneratorProviderState, error) {
  43. // If jsonSpec is provided, we need to extract the generator reference from it
  44. // However, for v2 generators, we already have the reference, so we can use that
  45. // But we should validate that the jsonSpec matches our stored reference if provided
  46. if jsonSpec != nil {
  47. // Parse the jsonSpec to extract metadata if needed
  48. var meta struct {
  49. Metadata struct {
  50. Name string `json:"name"`
  51. Namespace string `json:"namespace"`
  52. } `json:"metadata"`
  53. APIVersion string `json:"apiVersion"`
  54. Kind string `json:"kind"`
  55. }
  56. if err := json.Unmarshal(jsonSpec.Raw, &meta); err == nil {
  57. // Update the generator ref with the actual resource info
  58. if meta.Metadata.Name != "" {
  59. w.generatorRef.Name = meta.Metadata.Name
  60. }
  61. if meta.Metadata.Namespace != "" {
  62. w.generatorRef.Namespace = meta.Metadata.Namespace
  63. }
  64. if meta.APIVersion != "" {
  65. w.generatorRef.ApiVersion = meta.APIVersion
  66. }
  67. if meta.Kind != "" {
  68. w.generatorRef.Kind = meta.Kind
  69. }
  70. }
  71. }
  72. // Use the provided namespace as the source namespace
  73. sourceNs := namespace
  74. if sourceNs == "" {
  75. sourceNs = w.sourceNamespace
  76. }
  77. // Call the v2 gRPC Generate
  78. resp, err := w.client.Generate(ctx, &genpb.GenerateRequest{
  79. GeneratorRef: w.generatorRef,
  80. SourceNamespace: sourceNs,
  81. })
  82. if err != nil {
  83. return nil, nil, fmt.Errorf("failed to call v2 generator: %w", err)
  84. }
  85. // Convert state bytes to GeneratorProviderState
  86. var state genv1alpha1.GeneratorProviderState
  87. if len(resp.State) > 0 {
  88. state = &apiextensions.JSON{Raw: resp.State}
  89. }
  90. return resp.Secrets, state, nil
  91. }
  92. // Cleanup deletes any resources created during the Generate phase.
  93. func (w *Client) Cleanup(ctx context.Context, jsonSpec *apiextensions.JSON, state genv1alpha1.GeneratorProviderState, _ client.Client, namespace string) error {
  94. // Extract state bytes
  95. var stateBytes []byte
  96. if state != nil {
  97. stateBytes = state.Raw
  98. }
  99. // Use the provided namespace as the source namespace
  100. sourceNs := namespace
  101. if sourceNs == "" {
  102. sourceNs = w.sourceNamespace
  103. }
  104. // Call the v2 gRPC Cleanup
  105. _, err := w.client.Cleanup(ctx, &genpb.CleanupRequest{
  106. GeneratorRef: w.generatorRef,
  107. State: stateBytes,
  108. SourceNamespace: sourceNs,
  109. })
  110. if err != nil {
  111. return fmt.Errorf("failed to call v2 generator cleanup: %w", err)
  112. }
  113. return nil
  114. }