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 }