github.com/kubeshop/testkube@v1.17.23/pkg/secret/client.go (about)

     1  package secret
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"go.uber.org/zap"
     8  	v1 "k8s.io/api/core/v1"
     9  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    10  	corev1 "k8s.io/client-go/applyconfigurations/core/v1"
    11  	"k8s.io/client-go/kubernetes"
    12  
    13  	"github.com/kubeshop/testkube/pkg/k8sclient"
    14  	"github.com/kubeshop/testkube/pkg/log"
    15  )
    16  
    17  const testkubeTestSecretLabel = "tests-secrets"
    18  
    19  //go:generate mockgen -destination=./mock_client.go -package=secret "github.com/kubeshop/testkube/pkg/secret" Interface
    20  type Interface interface {
    21  	Get(id string, namespace ...string) (map[string]string, error)
    22  	GetObject(id string) (*v1.Secret, error)
    23  	List(all bool, namespace string) (map[string]map[string]string, error)
    24  	Create(id string, labels, stringData map[string]string, namespace ...string) error
    25  	Apply(id string, labels, stringData map[string]string) error
    26  	Update(id string, labels, stringData map[string]string) error
    27  	Delete(id string) error
    28  	DeleteAll(selector string) error
    29  }
    30  
    31  // Client provide methods to manage secrets
    32  type Client struct {
    33  	ClientSet *kubernetes.Clientset
    34  	Log       *zap.SugaredLogger
    35  	Namespace string
    36  }
    37  
    38  // NewClient is a method to create new secret client
    39  func NewClient(namespace string) (*Client, error) {
    40  	clientSet, err := k8sclient.ConnectToK8s()
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	return &Client{
    46  		ClientSet: clientSet,
    47  		Log:       log.DefaultLogger,
    48  		Namespace: namespace,
    49  	}, nil
    50  }
    51  
    52  // Get is a method to retrieve an existing secret
    53  func (c *Client) Get(id string, namespace ...string) (map[string]string, error) {
    54  	ns := c.Namespace
    55  	if len(namespace) != 0 {
    56  		ns = namespace[0]
    57  	}
    58  
    59  	secretsClient := c.ClientSet.CoreV1().Secrets(ns)
    60  	ctx := context.Background()
    61  
    62  	secretSpec, err := secretsClient.Get(ctx, id, metav1.GetOptions{})
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	stringData := map[string]string{}
    68  	for key, value := range secretSpec.Data {
    69  		stringData[key] = string(value)
    70  	}
    71  
    72  	return stringData, nil
    73  }
    74  
    75  // GetObject is a method to retrieve an existing secret object
    76  func (c *Client) GetObject(id string) (*v1.Secret, error) {
    77  	secretsClient := c.ClientSet.CoreV1().Secrets(c.Namespace)
    78  	ctx := context.Background()
    79  
    80  	secretSpec, err := secretsClient.Get(ctx, id, metav1.GetOptions{})
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	return secretSpec, nil
    86  }
    87  
    88  // List is a method to retrieve all existing secrets
    89  func (c *Client) List(all bool, namespace string) (map[string]map[string]string, error) {
    90  	if namespace == "" {
    91  		namespace = c.Namespace
    92  	}
    93  
    94  	secretsClient := c.ClientSet.CoreV1().Secrets(namespace)
    95  	ctx := context.Background()
    96  
    97  	selector := ""
    98  	if !all {
    99  		selector = fmt.Sprintf("createdBy=testkube")
   100  	}
   101  
   102  	secretList, err := secretsClient.List(ctx, metav1.ListOptions{
   103  		LabelSelector: selector})
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  
   108  	secretData := map[string]map[string]string{}
   109  	for _, item := range secretList.Items {
   110  		stringData := map[string]string{}
   111  		for key, value := range item.Data {
   112  			stringData[key] = string(value)
   113  		}
   114  
   115  		secretData[item.Name] = stringData
   116  	}
   117  
   118  	return secretData, nil
   119  }
   120  
   121  // Create is a method to create new secret
   122  func (c *Client) Create(id string, labels, stringData map[string]string, namespace ...string) error {
   123  	ns := c.Namespace
   124  	if len(namespace) != 0 {
   125  		ns = namespace[0]
   126  	}
   127  
   128  	secretsClient := c.ClientSet.CoreV1().Secrets(ns)
   129  	ctx := context.Background()
   130  
   131  	secretSpec := NewSpec(id, ns, labels, stringData)
   132  	if _, err := secretsClient.Create(ctx, secretSpec, metav1.CreateOptions{}); err != nil {
   133  		return err
   134  	}
   135  
   136  	return nil
   137  }
   138  
   139  // Apply is a method to create or update a secret
   140  func (c *Client) Apply(id string, labels, stringData map[string]string) error {
   141  	secretsClient := c.ClientSet.CoreV1().Secrets(c.Namespace)
   142  	ctx := context.Background()
   143  
   144  	secretSpec := NewApplySpec(id, c.Namespace, labels, stringData)
   145  	if _, err := secretsClient.Apply(ctx, secretSpec, metav1.ApplyOptions{
   146  		FieldManager: "application/apply-patch"}); err != nil {
   147  		return err
   148  	}
   149  
   150  	return nil
   151  }
   152  
   153  // Update is a method to update an existing secret
   154  func (c *Client) Update(id string, labels, stringData map[string]string) error {
   155  	secretsClient := c.ClientSet.CoreV1().Secrets(c.Namespace)
   156  	ctx := context.Background()
   157  
   158  	secretSpec := NewSpec(id, c.Namespace, labels, stringData)
   159  	if _, err := secretsClient.Update(ctx, secretSpec, metav1.UpdateOptions{}); err != nil {
   160  		return err
   161  	}
   162  
   163  	return nil
   164  }
   165  
   166  // Delete is a method to delete an existing secret
   167  func (c *Client) Delete(id string) error {
   168  	secretsClient := c.ClientSet.CoreV1().Secrets(c.Namespace)
   169  	ctx := context.Background()
   170  
   171  	if err := secretsClient.Delete(ctx, id, metav1.DeleteOptions{}); err != nil {
   172  		return err
   173  	}
   174  
   175  	return nil
   176  }
   177  
   178  // DeleteAll is a method to delete all existing secrets
   179  func (c *Client) DeleteAll(selector string) error {
   180  	secretsClient := c.ClientSet.CoreV1().Secrets(c.Namespace)
   181  	ctx := context.Background()
   182  
   183  	filter := fmt.Sprintf("testkube=%s", testkubeTestSecretLabel)
   184  	if selector != "" {
   185  		filter += "," + selector
   186  	}
   187  
   188  	if err := secretsClient.DeleteCollection(ctx, metav1.DeleteOptions{},
   189  		metav1.ListOptions{LabelSelector: filter}); err != nil {
   190  		return err
   191  	}
   192  
   193  	return nil
   194  }
   195  
   196  // NewSpec is a method to return secret spec
   197  func NewSpec(id, namespace string, labels, stringData map[string]string) *v1.Secret {
   198  	configuration := &v1.Secret{
   199  		ObjectMeta: metav1.ObjectMeta{
   200  			Name:      id,
   201  			Namespace: namespace,
   202  			Labels:    map[string]string{"testkube": testkubeTestSecretLabel, "createdBy": "testkube"},
   203  		},
   204  		Type:       v1.SecretTypeOpaque,
   205  		StringData: stringData,
   206  	}
   207  
   208  	for key, value := range labels {
   209  		configuration.Labels[key] = value
   210  	}
   211  
   212  	return configuration
   213  }
   214  
   215  // NewApplySpec is a method to return secret apply spec
   216  func NewApplySpec(id, namespace string, labels, stringData map[string]string) *corev1.SecretApplyConfiguration {
   217  	configuration := corev1.Secret(id, namespace).
   218  		WithLabels(map[string]string{"testkube": testkubeTestSecretLabel}).
   219  		WithStringData(stringData).
   220  		WithType(v1.SecretTypeOpaque)
   221  
   222  	for key, value := range labels {
   223  		configuration.Labels[key] = value
   224  	}
   225  
   226  	return configuration
   227  }
   228  
   229  // GetMetadataName returns secret metadata name
   230  func GetMetadataName(name string) string {
   231  	return fmt.Sprintf("%s-secrets", name)
   232  }