github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/cmd/deck/abort.go (about)

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"fmt"
    23  	"net/http"
    24  
    25  	"github.com/sirupsen/logrus"
    26  	kerrors "k8s.io/apimachinery/pkg/api/errors"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	ktypes "k8s.io/apimachinery/pkg/types"
    29  	prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1"
    30  	prowv1 "sigs.k8s.io/prow/pkg/client/clientset/versioned/typed/prowjobs/v1"
    31  	"sigs.k8s.io/prow/pkg/githuboauth"
    32  	"sigs.k8s.io/prow/pkg/plugins"
    33  )
    34  
    35  func handleAbort(prowJobClient prowv1.ProwJobInterface, cfg authCfgGetter, goa *githuboauth.Agent, ghc githuboauth.AuthenticatedUserIdentifier, cli deckGitHubClient, pluginAgent *plugins.ConfigAgent, log *logrus.Entry) http.HandlerFunc {
    36  	return func(w http.ResponseWriter, r *http.Request) {
    37  		ctx := context.TODO()
    38  		name := r.URL.Query().Get("prowjob")
    39  		l := log.WithField("prowjob", name)
    40  		if name == "" {
    41  			http.Error(w, "Request did not provide the 'prowjob' query parameter.", http.StatusBadRequest)
    42  			return
    43  		}
    44  		pj, err := prowJobClient.Get(ctx, name, metav1.GetOptions{})
    45  		if err != nil {
    46  			http.Error(w, fmt.Sprintf("ProwJob not found: %v.", err), http.StatusNotFound)
    47  			if !kerrors.IsNotFound(err) {
    48  				// admins only care about errors other than not found
    49  				l.WithError(err).Warning("ProwJob not found.")
    50  			}
    51  			return
    52  		}
    53  		switch r.Method {
    54  		case http.MethodPost:
    55  			if pj.Status.State != prowapi.TriggeredState && pj.Status.State != prowapi.PendingState {
    56  				http.Error(w, fmt.Sprintf("Cannot abort job with state: %q.", pj.Status.State), http.StatusBadRequest)
    57  				l.Debug("Cannot abort job with state.")
    58  				return
    59  			}
    60  			// Using same permission validation as rerun, could be future work to add validation
    61  			// unique to Abort
    62  			allowed, user, err, code := isAllowedToRerun(r, cfg, goa, ghc, *pj, cli, pluginAgent, l)
    63  			if err != nil {
    64  				http.Error(w, fmt.Sprintf("Could not verify if allowed to abort: %v.", err), code)
    65  				l.WithError(err).Debug("Could not verify if allowed to abort.")
    66  				return
    67  			}
    68  			l = l.WithField("allowed", allowed)
    69  			l.Info("Attempted abort")
    70  			if !allowed {
    71  				http.Error(w, "You don't have permission to abort this job.", http.StatusUnauthorized)
    72  				l.Debug("You don't have permission to abort this job.")
    73  				return
    74  			}
    75  			var abortDescription string
    76  			if len(user) > 0 {
    77  				abortDescription = fmt.Sprintf("%v successfully aborted %v.", user, name)
    78  			} else {
    79  				abortDescription = fmt.Sprintf("Successfully aborted %v.", name)
    80  			}
    81  			pj.Status.State = prowapi.AbortedState
    82  			pj.Status.Description = abortDescription
    83  			jsonPJ, err := json.Marshal(pj)
    84  			if err != nil {
    85  				http.Error(w, fmt.Sprintf("Error marshal source job: %v.", err), http.StatusInternalServerError)
    86  				l.WithError(err).Errorf("Error marshal source job.")
    87  				return
    88  			}
    89  			pj, err := prowJobClient.Patch(ctx, pj.Name, ktypes.MergePatchType, jsonPJ, metav1.PatchOptions{})
    90  			if err != nil {
    91  				http.Error(w, fmt.Sprintf("Could not patch aborted job: %v.", err), http.StatusInternalServerError)
    92  				l.WithError(err).Errorf("Could not patch aborted job.")
    93  				return
    94  			}
    95  			l.Info(abortDescription)
    96  			if _, err = w.Write([]byte("Job successfully aborted.")); err != nil {
    97  				l.WithError(err).Debug(fmt.Sprintf("Error writing to abort response for %v.", pj.Name))
    98  			}
    99  			return
   100  		default:
   101  			http.Error(w, fmt.Sprintf("bad verb %v", r.Method), http.StatusMethodNotAllowed)
   102  			return
   103  		}
   104  	}
   105  }