externalsecret_controller_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  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 externalsecret
  13. import (
  14. "context"
  15. "fmt"
  16. "time"
  17. . "github.com/onsi/ginkgo"
  18. . "github.com/onsi/gomega"
  19. dto "github.com/prometheus/client_model/go"
  20. v1 "k8s.io/api/core/v1"
  21. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  22. "k8s.io/apimachinery/pkg/types"
  23. "k8s.io/apimachinery/pkg/util/wait"
  24. "sigs.k8s.io/controller-runtime/pkg/client"
  25. esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  26. "github.com/external-secrets/external-secrets/pkg/provider"
  27. "github.com/external-secrets/external-secrets/pkg/provider/fake"
  28. "github.com/external-secrets/external-secrets/pkg/provider/schema"
  29. )
  30. var (
  31. fakeProvider *fake.Client
  32. metric dto.Metric
  33. timeout = time.Second * 30
  34. interval = time.Millisecond * 250
  35. )
  36. var _ = Describe("ExternalSecret controller", func() {
  37. const (
  38. ExternalSecretName = "test-es"
  39. ExternalSecretStore = "test-store"
  40. ExternalSecretTargetSecretName = "test-secret"
  41. )
  42. var ExternalSecretNamespace string
  43. BeforeEach(func() {
  44. var err error
  45. ExternalSecretNamespace, err = CreateNamespace("test-ns", k8sClient)
  46. Expect(err).ToNot(HaveOccurred())
  47. Expect(k8sClient.Create(context.Background(), &esv1alpha1.SecretStore{
  48. ObjectMeta: metav1.ObjectMeta{
  49. Name: ExternalSecretStore,
  50. Namespace: ExternalSecretNamespace,
  51. },
  52. Spec: esv1alpha1.SecretStoreSpec{
  53. Provider: &esv1alpha1.SecretStoreProvider{
  54. AWS: &esv1alpha1.AWSProvider{
  55. Service: esv1alpha1.AWSServiceSecretsManager,
  56. },
  57. },
  58. },
  59. })).To(Succeed())
  60. metric.Reset()
  61. syncCallsTotal.Reset()
  62. syncCallsError.Reset()
  63. externalSecretCondition.Reset()
  64. })
  65. AfterEach(func() {
  66. Expect(k8sClient.Delete(context.Background(), &v1.Namespace{
  67. ObjectMeta: metav1.ObjectMeta{
  68. Name: ExternalSecretNamespace,
  69. },
  70. }, client.PropagationPolicy(metav1.DeletePropagationBackground)), client.GracePeriodSeconds(0)).To(Succeed())
  71. Expect(k8sClient.Delete(context.Background(), &esv1alpha1.SecretStore{
  72. ObjectMeta: metav1.ObjectMeta{
  73. Name: ExternalSecretStore,
  74. Namespace: ExternalSecretNamespace,
  75. },
  76. }, client.PropagationPolicy(metav1.DeletePropagationBackground)), client.GracePeriodSeconds(0)).To(Succeed())
  77. })
  78. Context("When creating an ExternalSecret", func() {
  79. It("should set the condition eventually", func() {
  80. ctx := context.Background()
  81. es := &esv1alpha1.ExternalSecret{
  82. ObjectMeta: metav1.ObjectMeta{
  83. Name: ExternalSecretName,
  84. Namespace: ExternalSecretNamespace,
  85. },
  86. Spec: esv1alpha1.ExternalSecretSpec{
  87. SecretStoreRef: esv1alpha1.SecretStoreRef{
  88. Name: ExternalSecretStore,
  89. },
  90. Target: esv1alpha1.ExternalSecretTarget{
  91. Name: ExternalSecretTargetSecretName,
  92. },
  93. },
  94. }
  95. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  96. esLookupKey := types.NamespacedName{Name: ExternalSecretName, Namespace: ExternalSecretNamespace}
  97. createdES := &esv1alpha1.ExternalSecret{}
  98. Eventually(func() bool {
  99. err := k8sClient.Get(ctx, esLookupKey, createdES)
  100. if err != nil {
  101. return false
  102. }
  103. cond := GetExternalSecretCondition(createdES.Status, esv1alpha1.ExternalSecretReady)
  104. if cond == nil || cond.Status != v1.ConditionTrue {
  105. return false
  106. }
  107. return true
  108. }, timeout, interval).Should(BeTrue())
  109. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 0.0)).To(BeTrue())
  110. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 1.0)).To(BeTrue())
  111. Eventually(func() bool {
  112. Expect(syncCallsTotal.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
  113. return metric.GetCounter().GetValue() >= 2.0
  114. }, timeout, interval).Should(BeTrue())
  115. })
  116. })
  117. Context("When updating an ExternalSecret", func() {
  118. It("should increment the syncCallsTotal metric", func() {
  119. ctx := context.Background()
  120. es := &esv1alpha1.ExternalSecret{
  121. ObjectMeta: metav1.ObjectMeta{
  122. Name: ExternalSecretName,
  123. Namespace: ExternalSecretNamespace,
  124. },
  125. Spec: esv1alpha1.ExternalSecretSpec{
  126. SecretStoreRef: esv1alpha1.SecretStoreRef{
  127. Name: ExternalSecretStore,
  128. },
  129. Target: esv1alpha1.ExternalSecretTarget{
  130. Name: ExternalSecretTargetSecretName,
  131. },
  132. },
  133. }
  134. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  135. createdES := &esv1alpha1.ExternalSecret{}
  136. Eventually(func() error {
  137. esLookupKey := types.NamespacedName{Name: ExternalSecretName, Namespace: ExternalSecretNamespace}
  138. err := k8sClient.Get(ctx, esLookupKey, createdES)
  139. if err != nil {
  140. return err
  141. }
  142. createdES.Spec.RefreshInterval = &metav1.Duration{Duration: 10 * time.Second}
  143. err = k8sClient.Update(ctx, createdES)
  144. if err != nil {
  145. return err
  146. }
  147. return nil
  148. }, timeout, interval).Should(Succeed())
  149. Eventually(func() bool {
  150. Expect(syncCallsTotal.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
  151. return metric.GetCounter().GetValue() >= 3.0
  152. }, timeout, interval).Should(BeTrue())
  153. })
  154. })
  155. Context("When syncing ExternalSecret value", func() {
  156. It("should set the secret value and sync labels/annotations", func() {
  157. ctx := context.Background()
  158. const targetProp = "targetProperty"
  159. const secretVal = "someValue"
  160. es := &esv1alpha1.ExternalSecret{
  161. ObjectMeta: metav1.ObjectMeta{
  162. Name: ExternalSecretName,
  163. Namespace: ExternalSecretNamespace,
  164. Labels: map[string]string{
  165. "fooobar": "bazz",
  166. "bazzing": "booze",
  167. },
  168. Annotations: map[string]string{
  169. "hihihih": "hehehe",
  170. "harharhra": "yallayalla",
  171. },
  172. },
  173. Spec: esv1alpha1.ExternalSecretSpec{
  174. SecretStoreRef: esv1alpha1.SecretStoreRef{
  175. Name: ExternalSecretStore,
  176. },
  177. Target: esv1alpha1.ExternalSecretTarget{
  178. Name: ExternalSecretTargetSecretName,
  179. },
  180. Data: []esv1alpha1.ExternalSecretData{
  181. {
  182. SecretKey: targetProp,
  183. RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
  184. Key: "barz",
  185. Property: "bang",
  186. },
  187. },
  188. },
  189. },
  190. }
  191. fakeProvider.WithGetSecret([]byte(secretVal), nil)
  192. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  193. secretLookupKey := types.NamespacedName{
  194. Name: ExternalSecretTargetSecretName,
  195. Namespace: ExternalSecretNamespace}
  196. syncedSecret := &v1.Secret{}
  197. Eventually(func() bool {
  198. err := k8sClient.Get(ctx, secretLookupKey, syncedSecret)
  199. if err != nil {
  200. return false
  201. }
  202. v := syncedSecret.Data[targetProp]
  203. return string(v) == secretVal
  204. }, timeout, interval).Should(BeTrue())
  205. Expect(syncedSecret.ObjectMeta.Labels).To(BeEquivalentTo(es.ObjectMeta.Labels))
  206. Expect(syncedSecret.ObjectMeta.Annotations).To(BeEquivalentTo(es.ObjectMeta.Annotations))
  207. })
  208. It("should set the secret value and use the provided secret template", func() {
  209. By("creating an ExternalSecret")
  210. ctx := context.Background()
  211. const targetProp = "targetProperty"
  212. const secretVal = "someValue"
  213. const templateSecretKey = "tplkey"
  214. const templateSecretVal = "{{ .targetProperty | toString | upper }}"
  215. es := &esv1alpha1.ExternalSecret{
  216. ObjectMeta: metav1.ObjectMeta{
  217. Name: ExternalSecretName,
  218. Namespace: ExternalSecretNamespace,
  219. Labels: map[string]string{
  220. "fooobar": "bazz",
  221. },
  222. Annotations: map[string]string{
  223. "hihihih": "hehehe",
  224. },
  225. },
  226. Spec: esv1alpha1.ExternalSecretSpec{
  227. SecretStoreRef: esv1alpha1.SecretStoreRef{
  228. Name: ExternalSecretStore,
  229. },
  230. Target: esv1alpha1.ExternalSecretTarget{
  231. Name: ExternalSecretTargetSecretName,
  232. Template: &esv1alpha1.ExternalSecretTemplate{
  233. Metadata: esv1alpha1.ExternalSecretTemplateMetadata{
  234. Labels: map[string]string{
  235. "foos": "ball",
  236. },
  237. Annotations: map[string]string{
  238. "hihi": "ga",
  239. },
  240. },
  241. Data: map[string]string{
  242. templateSecretKey: templateSecretVal,
  243. },
  244. },
  245. },
  246. Data: []esv1alpha1.ExternalSecretData{
  247. {
  248. SecretKey: targetProp,
  249. RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
  250. Key: "barz",
  251. Property: "bang",
  252. },
  253. },
  254. },
  255. },
  256. }
  257. fakeProvider.WithGetSecret([]byte(secretVal), nil)
  258. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  259. secretLookupKey := types.NamespacedName{
  260. Name: ExternalSecretTargetSecretName,
  261. Namespace: ExternalSecretNamespace}
  262. syncedSecret := &v1.Secret{}
  263. Eventually(func() bool {
  264. err := k8sClient.Get(ctx, secretLookupKey, syncedSecret)
  265. if err != nil {
  266. return false
  267. }
  268. v1 := syncedSecret.Data[targetProp]
  269. v2 := syncedSecret.Data[templateSecretKey]
  270. return string(v1) == secretVal && string(v2) == "SOMEVALUE" // templated
  271. }, timeout, interval).Should(BeTrue())
  272. Expect(syncedSecret.ObjectMeta.Labels).To(BeEquivalentTo(
  273. es.Spec.Target.Template.Metadata.Labels))
  274. Expect(syncedSecret.ObjectMeta.Annotations).To(BeEquivalentTo(
  275. es.Spec.Target.Template.Metadata.Annotations))
  276. })
  277. It("should refresh secret value", func() {
  278. ctx := context.Background()
  279. const targetProp = "targetProperty"
  280. const secretVal = "someValue"
  281. es := &esv1alpha1.ExternalSecret{
  282. ObjectMeta: metav1.ObjectMeta{
  283. Name: ExternalSecretName,
  284. Namespace: ExternalSecretNamespace,
  285. },
  286. Spec: esv1alpha1.ExternalSecretSpec{
  287. RefreshInterval: &metav1.Duration{Duration: time.Second},
  288. SecretStoreRef: esv1alpha1.SecretStoreRef{
  289. Name: ExternalSecretStore,
  290. },
  291. Target: esv1alpha1.ExternalSecretTarget{
  292. Name: ExternalSecretTargetSecretName,
  293. },
  294. Data: []esv1alpha1.ExternalSecretData{
  295. {
  296. SecretKey: targetProp,
  297. RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
  298. Key: "barz",
  299. },
  300. },
  301. },
  302. },
  303. }
  304. fakeProvider.WithGetSecret([]byte(secretVal), nil)
  305. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  306. secretLookupKey := types.NamespacedName{
  307. Name: ExternalSecretTargetSecretName,
  308. Namespace: ExternalSecretNamespace}
  309. syncedSecret := &v1.Secret{}
  310. Eventually(func() bool {
  311. err := k8sClient.Get(ctx, secretLookupKey, syncedSecret)
  312. if err != nil {
  313. return false
  314. }
  315. v := syncedSecret.Data[targetProp]
  316. return string(v) == secretVal
  317. }, timeout, interval).Should(BeTrue())
  318. newValue := "NEW VALUE"
  319. fakeProvider.WithGetSecret([]byte(newValue), nil)
  320. Eventually(func() bool {
  321. err := k8sClient.Get(ctx, secretLookupKey, syncedSecret)
  322. if err != nil {
  323. return false
  324. }
  325. v := syncedSecret.Data[targetProp]
  326. return string(v) == newValue
  327. }, timeout, interval).Should(BeTrue())
  328. })
  329. It("should fetch secrets using dataFrom", func() {
  330. ctx := context.Background()
  331. const secretVal = "someValue"
  332. es := &esv1alpha1.ExternalSecret{
  333. ObjectMeta: metav1.ObjectMeta{
  334. Name: ExternalSecretName,
  335. Namespace: ExternalSecretNamespace,
  336. },
  337. Spec: esv1alpha1.ExternalSecretSpec{
  338. SecretStoreRef: esv1alpha1.SecretStoreRef{
  339. Name: ExternalSecretStore,
  340. },
  341. Target: esv1alpha1.ExternalSecretTarget{
  342. Name: ExternalSecretTargetSecretName,
  343. },
  344. DataFrom: []esv1alpha1.ExternalSecretDataRemoteRef{
  345. {
  346. Key: "barz",
  347. },
  348. },
  349. },
  350. }
  351. fakeProvider.WithGetSecretMap(map[string][]byte{
  352. "foo": []byte("bar"),
  353. "baz": []byte("bang"),
  354. }, nil)
  355. fakeProvider.WithGetSecret([]byte(secretVal), nil)
  356. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  357. secretLookupKey := types.NamespacedName{
  358. Name: ExternalSecretTargetSecretName,
  359. Namespace: ExternalSecretNamespace}
  360. syncedSecret := &v1.Secret{}
  361. Eventually(func() bool {
  362. err := k8sClient.Get(ctx, secretLookupKey, syncedSecret)
  363. if err != nil {
  364. return false
  365. }
  366. x := syncedSecret.Data["foo"]
  367. y := syncedSecret.Data["baz"]
  368. return string(x) == "bar" && string(y) == "bang"
  369. }, timeout, interval).Should(BeTrue())
  370. })
  371. It("should set an error condition when provider errors", func() {
  372. ctx := context.Background()
  373. const targetProp = "targetProperty"
  374. es := &esv1alpha1.ExternalSecret{
  375. ObjectMeta: metav1.ObjectMeta{
  376. Name: ExternalSecretName,
  377. Namespace: ExternalSecretNamespace,
  378. },
  379. Spec: esv1alpha1.ExternalSecretSpec{
  380. SecretStoreRef: esv1alpha1.SecretStoreRef{
  381. Name: ExternalSecretStore,
  382. },
  383. Target: esv1alpha1.ExternalSecretTarget{
  384. Name: ExternalSecretTargetSecretName,
  385. },
  386. Data: []esv1alpha1.ExternalSecretData{
  387. {
  388. SecretKey: targetProp,
  389. RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
  390. Key: "barz",
  391. Property: "bang",
  392. },
  393. },
  394. },
  395. },
  396. }
  397. fakeProvider.WithGetSecret(nil, fmt.Errorf("artificial testing error"))
  398. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  399. esLookupKey := types.NamespacedName{
  400. Name: ExternalSecretName,
  401. Namespace: ExternalSecretNamespace}
  402. createdES := &esv1alpha1.ExternalSecret{}
  403. Eventually(func() bool {
  404. err := k8sClient.Get(ctx, esLookupKey, createdES)
  405. if err != nil {
  406. return false
  407. }
  408. // condition must be false
  409. cond := GetExternalSecretCondition(createdES.Status, esv1alpha1.ExternalSecretReady)
  410. if cond == nil || cond.Status != v1.ConditionFalse || cond.Reason != esv1alpha1.ConditionReasonSecretSyncedError {
  411. return false
  412. }
  413. return true
  414. }, timeout, interval).Should(BeTrue())
  415. Eventually(func() bool {
  416. Expect(syncCallsError.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
  417. return metric.GetCounter().GetValue() >= 2.0
  418. }, timeout, interval).Should(BeTrue())
  419. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 1.0)).To(BeTrue())
  420. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 0.0)).To(BeTrue())
  421. })
  422. It("should set an error condition when store does not exist", func() {
  423. ctx := context.Background()
  424. const targetProp = "targetProperty"
  425. es := &esv1alpha1.ExternalSecret{
  426. ObjectMeta: metav1.ObjectMeta{
  427. Name: ExternalSecretName,
  428. Namespace: ExternalSecretNamespace,
  429. },
  430. Spec: esv1alpha1.ExternalSecretSpec{
  431. SecretStoreRef: esv1alpha1.SecretStoreRef{
  432. Name: "storeshouldnotexist",
  433. },
  434. Target: esv1alpha1.ExternalSecretTarget{
  435. Name: ExternalSecretTargetSecretName,
  436. },
  437. Data: []esv1alpha1.ExternalSecretData{
  438. {
  439. SecretKey: targetProp,
  440. RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
  441. Key: "barz",
  442. Property: "bang",
  443. },
  444. },
  445. },
  446. },
  447. }
  448. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  449. esLookupKey := types.NamespacedName{
  450. Name: ExternalSecretName,
  451. Namespace: ExternalSecretNamespace}
  452. createdES := &esv1alpha1.ExternalSecret{}
  453. Eventually(func() bool {
  454. err := k8sClient.Get(ctx, esLookupKey, createdES)
  455. if err != nil {
  456. return false
  457. }
  458. // condition must be false
  459. cond := GetExternalSecretCondition(createdES.Status, esv1alpha1.ExternalSecretReady)
  460. if cond == nil || cond.Status != v1.ConditionFalse || cond.Reason != esv1alpha1.ConditionReasonSecretSyncedError {
  461. return false
  462. }
  463. return true
  464. }, timeout, interval).Should(BeTrue())
  465. Eventually(func() bool {
  466. Expect(syncCallsError.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
  467. return metric.GetCounter().GetValue() >= 2.0
  468. }, timeout, interval).Should(BeTrue())
  469. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 1.0)).To(BeTrue())
  470. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 0.0)).To(BeTrue())
  471. })
  472. It("should set an error condition when store provider constructor fails", func() {
  473. ctx := context.Background()
  474. const targetProp = "targetProperty"
  475. es := &esv1alpha1.ExternalSecret{
  476. ObjectMeta: metav1.ObjectMeta{
  477. Name: ExternalSecretName,
  478. Namespace: ExternalSecretNamespace,
  479. },
  480. Spec: esv1alpha1.ExternalSecretSpec{
  481. SecretStoreRef: esv1alpha1.SecretStoreRef{
  482. Name: ExternalSecretStore,
  483. },
  484. Target: esv1alpha1.ExternalSecretTarget{
  485. Name: ExternalSecretTargetSecretName,
  486. },
  487. Data: []esv1alpha1.ExternalSecretData{
  488. {
  489. SecretKey: targetProp,
  490. RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
  491. Key: "barz",
  492. Property: "bang",
  493. },
  494. },
  495. },
  496. },
  497. }
  498. fakeProvider.WithNew(func(context.Context, esv1alpha1.GenericStore, client.Client,
  499. string) (provider.SecretsClient, error) {
  500. return nil, fmt.Errorf("artificial constructor error")
  501. })
  502. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  503. esLookupKey := types.NamespacedName{
  504. Name: ExternalSecretName,
  505. Namespace: ExternalSecretNamespace}
  506. createdES := &esv1alpha1.ExternalSecret{}
  507. Eventually(func() bool {
  508. err := k8sClient.Get(ctx, esLookupKey, createdES)
  509. if err != nil {
  510. return false
  511. }
  512. // condition must be false
  513. cond := GetExternalSecretCondition(createdES.Status, esv1alpha1.ExternalSecretReady)
  514. if cond == nil || cond.Status != v1.ConditionFalse || cond.Reason != esv1alpha1.ConditionReasonSecretSyncedError {
  515. return false
  516. }
  517. return true
  518. }, timeout, interval).Should(BeTrue())
  519. Eventually(func() bool {
  520. Expect(syncCallsError.WithLabelValues(ExternalSecretName, ExternalSecretNamespace).Write(&metric)).To(Succeed())
  521. return metric.GetCounter().GetValue() >= 2.0
  522. }, timeout, interval).Should(BeTrue())
  523. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 1.0)).To(BeTrue())
  524. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 0.0)).To(BeTrue())
  525. })
  526. It("should not process stores with mismatching controller field", func() {
  527. ctx := context.Background()
  528. storeName := "example-ts-foo"
  529. Expect(k8sClient.Create(context.Background(), &esv1alpha1.SecretStore{
  530. ObjectMeta: metav1.ObjectMeta{
  531. Name: storeName,
  532. Namespace: ExternalSecretNamespace,
  533. },
  534. Spec: esv1alpha1.SecretStoreSpec{
  535. Controller: "some-other-controller",
  536. Provider: &esv1alpha1.SecretStoreProvider{
  537. AWS: &esv1alpha1.AWSProvider{
  538. Service: esv1alpha1.AWSServiceSecretsManager,
  539. },
  540. },
  541. },
  542. })).To(Succeed())
  543. defer func() {
  544. Expect(k8sClient.Delete(context.Background(), &esv1alpha1.SecretStore{
  545. ObjectMeta: metav1.ObjectMeta{
  546. Name: storeName,
  547. Namespace: ExternalSecretNamespace,
  548. },
  549. })).To(Succeed())
  550. }()
  551. es := &esv1alpha1.ExternalSecret{
  552. ObjectMeta: metav1.ObjectMeta{
  553. Name: ExternalSecretName,
  554. Namespace: ExternalSecretNamespace,
  555. },
  556. Spec: esv1alpha1.ExternalSecretSpec{
  557. SecretStoreRef: esv1alpha1.SecretStoreRef{
  558. Name: storeName,
  559. },
  560. Target: esv1alpha1.ExternalSecretTarget{
  561. Name: ExternalSecretTargetSecretName,
  562. },
  563. Data: []esv1alpha1.ExternalSecretData{
  564. {
  565. SecretKey: "doesnothing",
  566. RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
  567. Key: "barz",
  568. Property: "bang",
  569. },
  570. },
  571. },
  572. },
  573. }
  574. Expect(k8sClient.Create(ctx, es)).Should(Succeed())
  575. secretLookupKey := types.NamespacedName{
  576. Name: ExternalSecretName,
  577. Namespace: ExternalSecretNamespace,
  578. }
  579. // COND
  580. createdES := &esv1alpha1.ExternalSecret{}
  581. Consistently(func() bool {
  582. err := k8sClient.Get(ctx, secretLookupKey, createdES)
  583. if err != nil {
  584. return false
  585. }
  586. cond := GetExternalSecretCondition(createdES.Status, esv1alpha1.ExternalSecretReady)
  587. return cond == nil
  588. }, timeout, interval).Should(BeTrue())
  589. // Condition True and False should be 0, since the Condition was not created
  590. Eventually(func() float64 {
  591. Expect(externalSecretCondition.WithLabelValues(ExternalSecretName, ExternalSecretNamespace, string(esv1alpha1.ExternalSecretReady), string(v1.ConditionTrue)).Write(&metric)).To(Succeed())
  592. return metric.GetGauge().GetValue()
  593. }, timeout, interval).Should(Equal(0.0))
  594. Eventually(func() float64 {
  595. Expect(externalSecretCondition.WithLabelValues(ExternalSecretName, ExternalSecretNamespace, string(esv1alpha1.ExternalSecretReady), string(v1.ConditionFalse)).Write(&metric)).To(Succeed())
  596. return metric.GetGauge().GetValue()
  597. }, timeout, interval).Should(Equal(0.0))
  598. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionFalse, 0.0)).To(BeTrue())
  599. Expect(externalSecretConditionShouldBe(ExternalSecretName, ExternalSecretNamespace, esv1alpha1.ExternalSecretReady, v1.ConditionTrue, 0.0)).To(BeTrue())
  600. })
  601. })
  602. })
  603. // CreateNamespace creates a new namespace in the cluster.
  604. func CreateNamespace(baseName string, c client.Client) (string, error) {
  605. genName := fmt.Sprintf("ctrl-test-%v", baseName)
  606. ns := &v1.Namespace{
  607. ObjectMeta: metav1.ObjectMeta{
  608. GenerateName: genName,
  609. },
  610. }
  611. var err error
  612. err = wait.Poll(time.Second, 10*time.Second, func() (bool, error) {
  613. err = c.Create(context.Background(), ns)
  614. if err != nil {
  615. return false, nil
  616. }
  617. return true, nil
  618. })
  619. if err != nil {
  620. return "", err
  621. }
  622. return ns.Name, nil
  623. }
  624. func externalSecretConditionShouldBe(name, ns string, ct esv1alpha1.ExternalSecretConditionType, cs v1.ConditionStatus, v float64) bool {
  625. return Eventually(func() float64 {
  626. Expect(externalSecretCondition.WithLabelValues(name, ns, string(ct), string(cs)).Write(&metric)).To(Succeed())
  627. return metric.GetGauge().GetValue()
  628. }, timeout, interval).Should(Equal(v))
  629. }
  630. func init() {
  631. fakeProvider = fake.New()
  632. schema.ForceRegister(fakeProvider, &esv1alpha1.SecretStoreProvider{
  633. AWS: &esv1alpha1.AWSProvider{
  634. Service: esv1alpha1.AWSServiceSecretsManager,
  635. },
  636. })
  637. }