github.com/kubeshop/testkube@v1.17.23/internal/app/api/v1/executor.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  	executorsmapper "github.com/kubeshop/testkube/pkg/mapper/executors"
    16  )
    17  
    18  func (s TestkubeAPI) CreateExecutorHandler() fiber.Handler {
    19  	return func(c *fiber.Ctx) error {
    20  		errPrefix := "failed to create executor"
    21  		var executor executorv1.Executor
    22  		if string(c.Request().Header.ContentType()) == mediaTypeYAML {
    23  			executorSpec := string(c.Body())
    24  			decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(executorSpec), len(executorSpec))
    25  			if err := decoder.Decode(&executor); 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.ExecutorUpsertRequest
    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  				request.QuoteExecutorTextFields()
    37  				data, err := crd.GenerateYAML(crd.TemplateExecutor, []testkube.ExecutorUpsertRequest{request})
    38  				return s.getCRDs(c, data, err)
    39  			}
    40  
    41  			executor = executorsmapper.MapAPIToCRD(request)
    42  			executor.Namespace = s.Namespace
    43  		}
    44  
    45  		created, err := s.ExecutorsClient.Create(&executor)
    46  		if err != nil {
    47  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not create executor: %w", errPrefix, err))
    48  		}
    49  
    50  		s.Events.Notify(testkube.NewEvent(
    51  			testkube.EventCreated,
    52  			testkube.EventResourceExecutor,
    53  			created.Name,
    54  		))
    55  
    56  		c.Status(http.StatusCreated)
    57  		return c.JSON(created)
    58  	}
    59  }
    60  
    61  func (s TestkubeAPI) UpdateExecutorHandler() fiber.Handler {
    62  	return func(c *fiber.Ctx) error {
    63  		errPrefix := "failed to update executor"
    64  		var request testkube.ExecutorUpdateRequest
    65  		if string(c.Request().Header.ContentType()) == mediaTypeYAML {
    66  			var executor executorv1.Executor
    67  			executorSpec := string(c.Body())
    68  			decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(executorSpec), len(executorSpec))
    69  			if err := decoder.Decode(&executor); err != nil {
    70  				return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not parse yaml request: %w", errPrefix, err))
    71  			}
    72  
    73  			request = executorsmapper.MapSpecToUpdate(&executor)
    74  		} else {
    75  			err := c.BodyParser(&request)
    76  			if err != nil {
    77  				return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not parse json request: %w", errPrefix, err))
    78  			}
    79  		}
    80  
    81  		var name string
    82  		if request.Name != nil {
    83  			name = *request.Name
    84  		}
    85  		errPrefix = errPrefix + " " + name
    86  		// we need to get resource first and load its metadata.ResourceVersion
    87  		executor, err := s.ExecutorsClient.Get(name)
    88  		if err != nil {
    89  			if errors.IsNotFound(err) {
    90  				return s.Error(c, http.StatusNotFound, fmt.Errorf("%s: client found no executor: %w", errPrefix, err))
    91  			}
    92  
    93  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not get executor: %w", errPrefix, err))
    94  		}
    95  
    96  		// map update executor but load spec only to not override metadata.ResourceVersion
    97  		executorSpec := executorsmapper.MapUpdateToSpec(request, executor)
    98  
    99  		updatedExecutor, err := s.ExecutorsClient.Update(executorSpec)
   100  		if err != nil {
   101  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not update executor: %w", errPrefix, err))
   102  		}
   103  
   104  		s.Events.Notify(testkube.NewEvent(
   105  			testkube.EventUpdated,
   106  			testkube.EventResourceExecutor,
   107  			updatedExecutor.Name,
   108  		))
   109  
   110  		return c.JSON(updatedExecutor)
   111  	}
   112  }
   113  
   114  func (s TestkubeAPI) ListExecutorsHandler() fiber.Handler {
   115  	return func(c *fiber.Ctx) error {
   116  		errPrefix := "failed to list executors"
   117  		list, err := s.ExecutorsClient.List(c.Query("selector"))
   118  		if err != nil {
   119  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not list executors: %w", errPrefix, err))
   120  		}
   121  
   122  		if c.Accepts(mediaTypeJSON, mediaTypeYAML) == mediaTypeYAML {
   123  			results := []testkube.ExecutorUpsertRequest{}
   124  			for _, item := range list.Items {
   125  				result := executorsmapper.MapCRDToAPI(item)
   126  				result.QuoteExecutorTextFields()
   127  				results = append(results, result)
   128  			}
   129  
   130  			data, err := crd.GenerateYAML(crd.TemplateExecutor, results)
   131  			return s.getCRDs(c, data, err)
   132  		}
   133  
   134  		results := []testkube.ExecutorDetails{}
   135  		for _, item := range list.Items {
   136  			results = append(results, executorsmapper.MapExecutorCRDToExecutorDetails(item))
   137  
   138  		}
   139  		return c.JSON(results)
   140  	}
   141  }
   142  
   143  func (s TestkubeAPI) GetExecutorHandler() fiber.Handler {
   144  	return func(c *fiber.Ctx) error {
   145  		name := c.Params("name")
   146  		errPrefix := fmt.Sprintf("failed to get executor %s", name)
   147  
   148  		item, err := s.ExecutorsClient.Get(name)
   149  		if err != nil {
   150  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not get executor: %w", errPrefix, err))
   151  		}
   152  
   153  		if c.Accepts(mediaTypeJSON, mediaTypeYAML) == mediaTypeYAML {
   154  			result := executorsmapper.MapCRDToAPI(*item)
   155  			result.QuoteExecutorTextFields()
   156  			data, err := crd.GenerateYAML(crd.TemplateExecutor, []testkube.ExecutorUpsertRequest{result})
   157  			return s.getCRDs(c, data, err)
   158  		}
   159  
   160  		result := executorsmapper.MapExecutorCRDToExecutorDetails(*item)
   161  		return c.JSON(result)
   162  	}
   163  }
   164  
   165  func (s TestkubeAPI) DeleteExecutorHandler() fiber.Handler {
   166  	return func(c *fiber.Ctx) error {
   167  		name := c.Params("name")
   168  		errPrefix := fmt.Sprintf("failed to delete executor %s", name)
   169  
   170  		err := s.ExecutorsClient.Delete(name)
   171  		if err != nil {
   172  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not delete executor: %w", errPrefix, err))
   173  		}
   174  
   175  		s.Events.Notify(testkube.NewEvent(
   176  			testkube.EventDeleted,
   177  			testkube.EventResourceExecutor,
   178  			name,
   179  		))
   180  
   181  		c.Status(http.StatusNoContent)
   182  
   183  		return nil
   184  	}
   185  }
   186  
   187  func (s TestkubeAPI) DeleteExecutorsHandler() fiber.Handler {
   188  	return func(c *fiber.Ctx) error {
   189  		errPrefix := "failed to delete executors"
   190  		err := s.ExecutorsClient.DeleteByLabels(c.Query("selector"))
   191  		if err != nil {
   192  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not delete executors: %w", errPrefix, err))
   193  		}
   194  
   195  		c.Status(http.StatusNoContent)
   196  		return nil
   197  	}
   198  }
   199  
   200  func (s TestkubeAPI) GetExecutorByTestTypeHandler() fiber.Handler {
   201  	return func(c *fiber.Ctx) error {
   202  		errPrefix := "failed to get executor by test type"
   203  
   204  		testType := c.Query("testType", "")
   205  		if testType == "" {
   206  			return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not fine test type", errPrefix))
   207  		}
   208  
   209  		item, err := s.ExecutorsClient.GetByType(testType)
   210  		if err != nil {
   211  			return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not get executor: %w", errPrefix, err))
   212  		}
   213  
   214  		if c.Accepts(mediaTypeJSON, mediaTypeYAML) == mediaTypeYAML {
   215  			result := executorsmapper.MapCRDToAPI(*item)
   216  			result.QuoteExecutorTextFields()
   217  			data, err := crd.GenerateYAML(crd.TemplateExecutor, []testkube.ExecutorUpsertRequest{result})
   218  			return s.getCRDs(c, data, err)
   219  		}
   220  
   221  		result := executorsmapper.MapExecutorCRDToExecutorDetails(*item)
   222  		return c.JSON(result)
   223  	}
   224  }