chart.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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 addon
  14. import (
  15. "bytes"
  16. "fmt"
  17. "os"
  18. "os/exec"
  19. "path/filepath"
  20. . "github.com/onsi/ginkgo/v2"
  21. corev1 "k8s.io/api/core/v1"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. "github.com/external-secrets/external-secrets-e2e/framework/log"
  24. )
  25. // HelmChart installs the specified Chart into the cluster.
  26. type HelmChart struct {
  27. Namespace string
  28. ReleaseName string
  29. Chart string
  30. ChartVersion string
  31. Repo ChartRepo
  32. Vars []StringTuple
  33. Values []string
  34. Args []string
  35. config *Config
  36. }
  37. type ChartRepo struct {
  38. Name string
  39. URL string
  40. }
  41. type StringTuple struct {
  42. Key string
  43. Value string
  44. }
  45. // Setup stores the config in an internal field
  46. // to get access to the k8s api in orderto fetch logs.
  47. func (c *HelmChart) Setup(cfg *Config) error {
  48. c.config = cfg
  49. return nil
  50. }
  51. // Install adds the chart repo and installs the helm chart.
  52. func (c *HelmChart) Install() error {
  53. if helmDependencyUpdateEnabled() {
  54. args := []string{
  55. "dependency", "update", filepath.Join(AssetDir(), "deploy/charts/external-secrets"),
  56. }
  57. log.Logf("updating chart dependencies with args: %+q", args)
  58. cmd := exec.Command("helm", args...)
  59. output, err := cmd.CombinedOutput()
  60. if err != nil {
  61. return fmt.Errorf("unable to run update cmd: %w: %s", err, string(output))
  62. }
  63. }
  64. err := c.addRepo()
  65. if err != nil {
  66. return err
  67. }
  68. args := c.installArgs()
  69. log.Logf("installing chart with args: %+q", args)
  70. cmd := exec.Command("helm", args...)
  71. output, err := cmd.CombinedOutput()
  72. if err != nil {
  73. return fmt.Errorf("unable to run cmd: %w: %s", err, string(output))
  74. }
  75. log.Logf("finished running chart install")
  76. return nil
  77. }
  78. func helmDependencyUpdateEnabled() bool {
  79. return os.Getenv("E2E_SKIP_HELM_DEPENDENCY_UPDATE") != "true"
  80. }
  81. func (c *HelmChart) installArgs() []string {
  82. args := []string{"install", c.ReleaseName, c.Chart}
  83. if helmDependencyUpdateEnabled() {
  84. args = append(args, "--dependency-update")
  85. }
  86. args = append(args,
  87. "--debug",
  88. "--wait",
  89. "--timeout", "600s",
  90. "-o", "yaml",
  91. "--namespace", c.Namespace,
  92. )
  93. if c.ChartVersion != "" {
  94. args = append(args, "--version", c.ChartVersion)
  95. }
  96. for _, v := range c.Values {
  97. args = append(args, "--values", v)
  98. }
  99. for _, s := range c.Vars {
  100. args = append(args, "--set", fmt.Sprintf("%s=%s", s.Key, s.Value))
  101. }
  102. args = append(args, c.Args...)
  103. return args
  104. }
  105. // Uninstall removes the chart aswell as the repo.
  106. func (c *HelmChart) Uninstall() error {
  107. args := []string{"uninstall", "--namespace", c.Namespace, c.ReleaseName, "--wait"}
  108. cmd := exec.Command("helm", args...)
  109. output, err := cmd.CombinedOutput()
  110. if err != nil {
  111. return fmt.Errorf("unable to uninstall helm release: %w: %s", err, string(output))
  112. }
  113. return c.removeRepo()
  114. }
  115. func (c *HelmChart) addRepo() error {
  116. if c.Repo.Name == "" || c.Repo.URL == "" {
  117. return nil
  118. }
  119. var sout, serr bytes.Buffer
  120. args := []string{"repo", "add", c.Repo.Name, c.Repo.URL}
  121. cmd := exec.Command("helm", args...)
  122. cmd.Stdout = &sout
  123. cmd.Stderr = &serr
  124. err := cmd.Run()
  125. if err != nil {
  126. return fmt.Errorf("unable to add helm repo: %w: %s, %s", err, sout.String(), serr.String())
  127. }
  128. return nil
  129. }
  130. func (c *HelmChart) removeRepo() error {
  131. if c.Repo.Name == "" || c.Repo.URL == "" {
  132. return nil
  133. }
  134. args := []string{"repo", "remove", c.Repo.Name}
  135. cmd := exec.Command("helm", args...)
  136. output, err := cmd.CombinedOutput()
  137. if err != nil {
  138. return fmt.Errorf("unable to remove repo: %w: %s", err, string(output))
  139. }
  140. return nil
  141. }
  142. // Logs fetches the logs from all pods managed by this release
  143. // and prints them out.
  144. func (c *HelmChart) Logs() error {
  145. kc := c.config.KubeClientSet
  146. podList, err := kc.CoreV1().Pods(c.Namespace).List(
  147. GinkgoT().Context(),
  148. metav1.ListOptions{LabelSelector: "app.kubernetes.io/instance=" + c.ReleaseName})
  149. if err != nil {
  150. return err
  151. }
  152. log.Logf("logs: found %d pods", len(podList.Items))
  153. tailLines := int64(200)
  154. for i := range podList.Items {
  155. pod := podList.Items[i]
  156. for _, con := range pod.Spec.Containers {
  157. for _, b := range []bool{true, false} {
  158. resp := kc.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &corev1.PodLogOptions{
  159. Container: con.Name,
  160. Previous: b,
  161. TailLines: &tailLines,
  162. }).Do(GinkgoT().Context())
  163. err := resp.Error()
  164. if err != nil {
  165. continue
  166. }
  167. logs, err := resp.Raw()
  168. if err != nil {
  169. continue
  170. }
  171. log.Logf("[%s]: %s", c.ReleaseName, string(logs))
  172. }
  173. }
  174. }
  175. return nil
  176. }
  177. func (c *HelmChart) HasVar(key, value string) bool {
  178. for _, v := range c.Vars {
  179. if v.Key == key && v.Value == value {
  180. return true
  181. }
  182. }
  183. return false
  184. }