github.com/kubeshop/testkube@v1.17.23/internal/app/api/v1/webhook.go (about) 1 package v1 2 3 import ( 4 "bytes" 5 "fmt" 6 "net/http" 7 8 "github.com/gofiber/fiber/v2" 9 "k8s.io/apimachinery/pkg/api/errors" 10 "k8s.io/apimachinery/pkg/util/yaml" 11 12 executorv1 "github.com/kubeshop/testkube-operator/api/executor/v1" 13 "github.com/kubeshop/testkube/pkg/api/v1/testkube" 14 "github.com/kubeshop/testkube/pkg/crd" 15 webhooksmapper "github.com/kubeshop/testkube/pkg/mapper/webhooks" 16 ) 17 18 func (s TestkubeAPI) CreateWebhookHandler() fiber.Handler { 19 return func(c *fiber.Ctx) error { 20 errPrefix := "failed to create webhook" 21 var webhook executorv1.Webhook 22 if string(c.Request().Header.ContentType()) == mediaTypeYAML { 23 webhookSpec := string(c.Body()) 24 decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(webhookSpec), len(webhookSpec)) 25 if err := decoder.Decode(&webhook); err != nil { 26 return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not parse yaml request: %w", errPrefix, err)) 27 } 28 } else { 29 var request testkube.WebhookCreateRequest 30 err := c.BodyParser(&request) 31 if err != nil { 32 return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not parse json request: %w", errPrefix, err)) 33 } 34 35 if c.Accepts(mediaTypeJSON, mediaTypeYAML) == mediaTypeYAML { 36 if request.PayloadTemplate != "" { 37 request.PayloadTemplate = fmt.Sprintf("%q", request.PayloadTemplate) 38 } 39 40 data, err := crd.GenerateYAML(crd.TemplateWebhook, []testkube.WebhookCreateRequest{request}) 41 return s.getCRDs(c, data, err) 42 } 43 44 webhook = webhooksmapper.MapAPIToCRD(request) 45 webhook.Namespace = s.Namespace 46 } 47 48 created, err := s.WebhooksClient.Create(&webhook) 49 if err != nil { 50 return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not create webhook: %w", errPrefix, err)) 51 } 52 53 c.Status(http.StatusCreated) 54 return c.JSON(created) 55 } 56 } 57 58 func (s TestkubeAPI) UpdateWebhookHandler() fiber.Handler { 59 return func(c *fiber.Ctx) error { 60 errPrefix := "failed to update webhook" 61 var request testkube.WebhookUpdateRequest 62 if string(c.Request().Header.ContentType()) == mediaTypeYAML { 63 var webhook executorv1.Webhook 64 webhookSpec := string(c.Body()) 65 decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(webhookSpec), len(webhookSpec)) 66 if err := decoder.Decode(&webhook); err != nil { 67 return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not parse yaml request: %w", errPrefix, err)) 68 } 69 70 request = webhooksmapper.MapSpecToUpdate(&webhook) 71 } else { 72 err := c.BodyParser(&request) 73 if err != nil { 74 return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not parse json request: %w", errPrefix, err)) 75 } 76 } 77 78 var name string 79 if request.Name != nil { 80 name = *request.Name 81 } 82 errPrefix = errPrefix + " " + name 83 // we need to get resource first and load its metadata.ResourceVersion 84 webhook, err := s.WebhooksClient.Get(name) 85 if err != nil { 86 if errors.IsNotFound(err) { 87 return s.Error(c, http.StatusNotFound, fmt.Errorf("%s: client found no webhook: %w", errPrefix, err)) 88 } 89 90 return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not get webhook: %w", errPrefix, err)) 91 } 92 93 // map update webhook but load spec only to not override metadata.ResourceVersion 94 webhookSpec := webhooksmapper.MapUpdateToSpec(request, webhook) 95 96 updatedWebhook, err := s.WebhooksClient.Update(webhookSpec) 97 if err != nil { 98 return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not update webhook: %w", errPrefix, err)) 99 } 100 101 return c.JSON(updatedWebhook) 102 } 103 } 104 105 func (s TestkubeAPI) ListWebhooksHandler() fiber.Handler { 106 return func(c *fiber.Ctx) error { 107 errPrefix := "failed to list webhooks" 108 109 list, err := s.WebhooksClient.List(c.Query("selector")) 110 if err != nil { 111 return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not list webhooks: %w", errPrefix, err)) 112 } 113 114 results := testkube.Webhooks{} 115 for _, item := range list.Items { 116 results = append(results, webhooksmapper.MapCRDToAPI(item)) 117 118 } 119 120 if c.Accepts(mediaTypeJSON, mediaTypeYAML) == mediaTypeYAML { 121 for i := range results { 122 if results[i].PayloadTemplate != "" { 123 results[i].PayloadTemplate = fmt.Sprintf("%q", results[i].PayloadTemplate) 124 } 125 } 126 127 data, err := crd.GenerateYAML(crd.TemplateWebhook, results) 128 return s.getCRDs(c, data, err) 129 } 130 131 return c.JSON(results) 132 } 133 } 134 135 func (s TestkubeAPI) GetWebhookHandler() fiber.Handler { 136 return func(c *fiber.Ctx) error { 137 name := c.Params("name") 138 errPrefix := fmt.Sprintf("failed to get webhook %s", name) 139 140 item, err := s.WebhooksClient.Get(name) 141 if err != nil { 142 if errors.IsNotFound(err) { 143 return s.Error(c, http.StatusNotFound, fmt.Errorf("%s: webhook not found: %w", errPrefix, err)) 144 } 145 return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not get webhook: %w", errPrefix, err)) 146 } 147 148 result := webhooksmapper.MapCRDToAPI(*item) 149 if c.Accepts(mediaTypeJSON, mediaTypeYAML) == mediaTypeYAML { 150 if result.PayloadTemplate != "" { 151 result.PayloadTemplate = fmt.Sprintf("%q", result.PayloadTemplate) 152 } 153 154 data, err := crd.GenerateYAML(crd.TemplateWebhook, []testkube.Webhook{result}) 155 return s.getCRDs(c, data, err) 156 } 157 158 return c.JSON(result) 159 } 160 } 161 162 func (s TestkubeAPI) DeleteWebhookHandler() fiber.Handler { 163 return func(c *fiber.Ctx) error { 164 name := c.Params("name") 165 errPrefix := fmt.Sprintf("failed to delete webhook %s", name) 166 167 err := s.WebhooksClient.Delete(name) 168 if err != nil { 169 if errors.IsNotFound(err) { 170 return s.Error(c, http.StatusNotFound, fmt.Errorf("%s: webhook not found: %w", errPrefix, err)) 171 } 172 return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not delete webhook: %w", errPrefix, err)) 173 } 174 175 c.Status(http.StatusNoContent) 176 return nil 177 } 178 } 179 180 func (s TestkubeAPI) DeleteWebhooksHandler() fiber.Handler { 181 return func(c *fiber.Ctx) error { 182 errPrefix := "failed to delete webhooks" 183 184 err := s.WebhooksClient.DeleteByLabels(c.Query("selector")) 185 if err != nil { 186 return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not delete webhooks: %w", errPrefix, err)) 187 } 188 189 c.Status(http.StatusNoContent) 190 return nil 191 } 192 }