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 }