github.com/kubeshop/testkube@v1.17.23/internal/app/api/v1/template.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  	templatev1 "github.com/kubeshop/testkube-operator/api/template/v1"
    13  	"github.com/kubeshop/testkube/pkg/api/v1/testkube"
    14  	"github.com/kubeshop/testkube/pkg/crd"
    15  	templatesmapper "github.com/kubeshop/testkube/pkg/mapper/templates"
    16  )
    17  
    18  func (s TestkubeAPI) CreateTemplateHandler() fiber.Handler {
    19  	return func(c *fiber.Ctx) error {
    20  		errPrefix := "failed to create template"
    21  		var template templatev1.Template
    22  		if string(c.Request().Header.ContentType()) == mediaTypeYAML {
    23  			templateSpec := string(c.Body())
    24  			decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(templateSpec), len(templateSpec))
    25  			if err := decoder.Decode(&template); 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.TemplateCreateRequest
    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.Body != "" {
    37  					request.Body = fmt.Sprintf("%q", request.Body)
    38  				}
    39  
    40  				data, err := crd.GenerateYAML(crd.TemplateTemplate, []testkube.TemplateCreateRequest{request})
    41  				return s.getCRDs(c, data, err)
    42  			}
    43  
    44  			template = templatesmapper.MapAPIToCRD(request)
    45  			template.Namespace = s.Namespace
    46  		}
    47  
    48  		created, err := s.TemplatesClient.Create(&template)
    49  		if err != nil {
    50  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not create template: %w", errPrefix, err))
    51  		}
    52  
    53  		c.Status(http.StatusCreated)
    54  		return c.JSON(created)
    55  	}
    56  }
    57  
    58  func (s TestkubeAPI) UpdateTemplateHandler() fiber.Handler {
    59  	return func(c *fiber.Ctx) error {
    60  		errPrefix := "failed to update template"
    61  		var request testkube.TemplateUpdateRequest
    62  		if string(c.Request().Header.ContentType()) == mediaTypeYAML {
    63  			var template templatev1.Template
    64  			templateSpec := string(c.Body())
    65  			decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(templateSpec), len(templateSpec))
    66  			if err := decoder.Decode(&template); err != nil {
    67  				return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not parse yaml request: %w", errPrefix, err))
    68  			}
    69  
    70  			request = templatesmapper.MapSpecToUpdate(&template)
    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  		template, err := s.TemplatesClient.Get(name)
    85  		if err != nil {
    86  			if errors.IsNotFound(err) {
    87  				return s.Error(c, http.StatusNotFound, fmt.Errorf("%s: client found no template: %w", errPrefix, err))
    88  			}
    89  
    90  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not get template: %w", errPrefix, err))
    91  		}
    92  
    93  		// map update template but load spec only to not override metadata.ResourceVersion
    94  		templateSpec := templatesmapper.MapUpdateToSpec(request, template)
    95  
    96  		updatedTemplate, err := s.TemplatesClient.Update(templateSpec)
    97  		if err != nil {
    98  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not update template: %w", errPrefix, err))
    99  		}
   100  
   101  		return c.JSON(updatedTemplate)
   102  	}
   103  }
   104  
   105  func (s TestkubeAPI) ListTemplatesHandler() fiber.Handler {
   106  	return func(c *fiber.Ctx) error {
   107  		errPrefix := "failed to list templates"
   108  
   109  		list, err := s.TemplatesClient.List(c.Query("selector"))
   110  		if err != nil {
   111  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not list templates: %w", errPrefix, err))
   112  		}
   113  
   114  		results := []testkube.Template{}
   115  		for _, item := range list.Items {
   116  			results = append(results, templatesmapper.MapCRDToAPI(item))
   117  
   118  		}
   119  
   120  		if c.Accepts(mediaTypeJSON, mediaTypeYAML) == mediaTypeYAML {
   121  			for i := range results {
   122  				if results[i].Body != "" {
   123  					results[i].Body = fmt.Sprintf("%q", results[i].Body)
   124  				}
   125  			}
   126  
   127  			data, err := crd.GenerateYAML(crd.TemplateTemplate, results)
   128  			return s.getCRDs(c, data, err)
   129  		}
   130  
   131  		return c.JSON(results)
   132  	}
   133  }
   134  
   135  func (s TestkubeAPI) GetTemplateHandler() fiber.Handler {
   136  	return func(c *fiber.Ctx) error {
   137  		name := c.Params("name")
   138  		errPrefix := fmt.Sprintf("failed to get template %s", name)
   139  
   140  		item, err := s.TemplatesClient.Get(name)
   141  		if err != nil {
   142  			if errors.IsNotFound(err) {
   143  				return s.Error(c, http.StatusNotFound, fmt.Errorf("%s: template not found: %w", errPrefix, err))
   144  			}
   145  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not get template: %w", errPrefix, err))
   146  		}
   147  
   148  		result := templatesmapper.MapCRDToAPI(*item)
   149  		if c.Accepts(mediaTypeJSON, mediaTypeYAML) == mediaTypeYAML {
   150  			if result.Body != "" {
   151  				result.Body = fmt.Sprintf("%q", result.Body)
   152  			}
   153  
   154  			data, err := crd.GenerateYAML(crd.TemplateTemplate, []testkube.Template{result})
   155  			return s.getCRDs(c, data, err)
   156  		}
   157  
   158  		return c.JSON(result)
   159  	}
   160  }
   161  
   162  func (s TestkubeAPI) DeleteTemplateHandler() fiber.Handler {
   163  	return func(c *fiber.Ctx) error {
   164  		name := c.Params("name")
   165  		errPrefix := fmt.Sprintf("failed to delete template %s", name)
   166  
   167  		err := s.TemplatesClient.Delete(name)
   168  		if err != nil {
   169  			if errors.IsNotFound(err) {
   170  				return s.Error(c, http.StatusNotFound, fmt.Errorf("%s: template not found: %w", errPrefix, err))
   171  			}
   172  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not delete template: %w", errPrefix, err))
   173  		}
   174  
   175  		c.Status(http.StatusNoContent)
   176  		return nil
   177  	}
   178  }
   179  
   180  func (s TestkubeAPI) DeleteTemplatesHandler() fiber.Handler {
   181  	return func(c *fiber.Ctx) error {
   182  		errPrefix := "failed to delete templates"
   183  
   184  		err := s.TemplatesClient.DeleteByLabels(c.Query("selector"))
   185  		if err != nil {
   186  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not delete templates: %w", errPrefix, err))
   187  		}
   188  
   189  		c.Status(http.StatusNoContent)
   190  		return nil
   191  	}
   192  }