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  }