github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/plugin/builtin/manifest/load_command.go (about)

     1  package manifest
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"time"
     7  
     8  	"github.com/evergreen-ci/evergreen/model"
     9  	"github.com/evergreen-ci/evergreen/model/manifest"
    10  	"github.com/evergreen-ci/evergreen/plugin"
    11  	"github.com/evergreen-ci/evergreen/thirdparty"
    12  	"github.com/evergreen-ci/evergreen/util"
    13  	"github.com/mongodb/grip/slogger"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  // ManifestLoadCommand
    18  type ManifestLoadCommand struct{}
    19  
    20  func (mfc *ManifestLoadCommand) Name() string {
    21  	return ManifestLoadCmd
    22  }
    23  
    24  func (mfc *ManifestLoadCommand) Plugin() string {
    25  	return ManifestPluginName
    26  }
    27  
    28  // ManifestLoadCommand-specific implementation of ParseParams.
    29  func (mfc *ManifestLoadCommand) ParseParams(params map[string]interface{}) error {
    30  	return nil
    31  }
    32  
    33  // updateExpansions adds the expansions for the manifest's modules into the TaskConfig's Expansions.
    34  func (mfc *ManifestLoadCommand) updateExpansions(manifest *manifest.Manifest,
    35  	conf *model.TaskConfig) {
    36  	for moduleName := range manifest.Modules {
    37  		// put the url for the module in the expansions
    38  		conf.Expansions.Put(fmt.Sprintf("%v_rev", moduleName), manifest.Modules[moduleName].Revision)
    39  	}
    40  }
    41  
    42  // Load performs a GET on /manifest/load
    43  func (mfc *ManifestLoadCommand) Load(log plugin.Logger, pluginCom plugin.PluginCommunicator, conf *model.TaskConfig) error {
    44  	var loadedManifest *manifest.Manifest
    45  	var err error
    46  
    47  	retriableGet := util.RetriableFunc(
    48  		func() error {
    49  			resp, err := pluginCom.TaskGetJSON(ManifestLoadAPIEndpoint)
    50  			if resp != nil {
    51  				defer resp.Body.Close()
    52  			}
    53  			if err != nil {
    54  				//Some generic error trying to connect - try again
    55  				log.LogExecution(slogger.WARN, "Error connecting to API server: %v", err)
    56  				return util.RetriableError{err}
    57  			}
    58  			if resp != nil && resp.StatusCode != http.StatusOK {
    59  				log.LogExecution(slogger.WARN, "Unexpected status code %v, retrying", resp.StatusCode)
    60  				return util.RetriableError{errors.Errorf("Unexpected status code %v", resp.StatusCode)}
    61  			}
    62  			err = util.ReadJSONInto(resp.Body, &loadedManifest)
    63  			return err
    64  		})
    65  
    66  	_, err = util.Retry(retriableGet, 10, 1*time.Second)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	if loadedManifest == nil {
    71  		return errors.New("Manifest is empty")
    72  	}
    73  	mfc.updateExpansions(loadedManifest, conf)
    74  	return nil
    75  }
    76  
    77  // Implementation of Execute.
    78  func (mfc *ManifestLoadCommand) Execute(pluginLogger plugin.Logger,
    79  	pluginCom plugin.PluginCommunicator, conf *model.TaskConfig,
    80  	stop chan bool) error {
    81  
    82  	errChan := make(chan error)
    83  	go func() {
    84  		errChan <- mfc.Load(pluginLogger, pluginCom, conf)
    85  	}()
    86  
    87  	select {
    88  	case err := <-errChan:
    89  		return err
    90  	case <-stop:
    91  		pluginLogger.LogExecution(slogger.INFO, "Received signal to terminate"+
    92  			" execution of manifest load command")
    93  		return nil
    94  	}
    95  
    96  }
    97  
    98  // ManifestLoadHandler attempts to get the manifest, if it exists it updates the expansions and returns
    99  // If it does not exist it performs GitHub API calls for each of the project's modules and gets
   100  // the head revision of the branch and inserts it into the manifest collection.
   101  // If there is a duplicate key error, then do a find on the manifest again.
   102  func (mp *ManifestPlugin) ManifestLoadHandler(w http.ResponseWriter, r *http.Request) {
   103  	task := plugin.GetTask(r)
   104  	projectRef, err := model.FindOneProjectRef(task.Project)
   105  	if err != nil {
   106  		http.Error(w, fmt.Sprintf("projectRef not found for project %v: %v", task.Project, err), http.StatusBadRequest)
   107  		return
   108  	}
   109  	project, err := model.FindProject("", projectRef)
   110  	if err != nil {
   111  		http.Error(w, fmt.Sprintf("project not found for ProjectRef %v: %v", projectRef.Identifier, err),
   112  			http.StatusBadRequest)
   113  		return
   114  	}
   115  	if project == nil {
   116  		http.Error(w, fmt.Sprintf("empty project not found for ProjectRef %v: %v", projectRef.Identifier, err),
   117  			http.StatusBadRequest)
   118  		return
   119  	}
   120  	// try to get the manifest
   121  	currentManifest, err := manifest.FindOne(manifest.ById(task.Version))
   122  	if err != nil {
   123  		http.Error(w, fmt.Sprintf("error retrieving manifest with version id %v: %v", task.Version, err),
   124  			http.StatusBadRequest)
   125  		return
   126  	}
   127  	if currentManifest != nil {
   128  		plugin.WriteJSON(w, http.StatusOK, currentManifest)
   129  		return
   130  	}
   131  
   132  	if task.Version == "" {
   133  		http.Error(w, fmt.Sprintf("versionId is empty"), http.StatusNotFound)
   134  		return
   135  	}
   136  
   137  	// attempt to insert a manifest after making GitHub API calls
   138  	newManifest := &manifest.Manifest{
   139  		Id:          task.Version,
   140  		Revision:    task.Revision,
   141  		ProjectName: task.Project,
   142  		Branch:      project.Branch,
   143  	}
   144  	// populate modules
   145  	var gitBranch *thirdparty.BranchEvent
   146  	modules := make(map[string]*manifest.Module)
   147  	for _, module := range project.Modules {
   148  		owner, repo := module.GetRepoOwnerAndName()
   149  		gitBranch, err = thirdparty.GetBranchEvent(mp.OAuthCredentials, owner, repo, module.Branch)
   150  		if err != nil {
   151  			http.Error(w, fmt.Sprintf("error retrieving getting git branch for module %v: %v", module.Name, err),
   152  				http.StatusInternalServerError)
   153  			return
   154  		}
   155  
   156  		modules[module.Name] = &manifest.Module{
   157  			Branch:   module.Branch,
   158  			Revision: gitBranch.Commit.SHA,
   159  			Repo:     repo,
   160  			Owner:    owner,
   161  			URL:      gitBranch.Commit.Url,
   162  		}
   163  	}
   164  	newManifest.Modules = modules
   165  	duplicate, err := newManifest.TryInsert()
   166  	if err != nil {
   167  		http.Error(w, fmt.Sprintf("error inserting manifest for %v: %v", newManifest.ProjectName, err),
   168  			http.StatusInternalServerError)
   169  		return
   170  	}
   171  	// if it is a duplicate, load the manifest again`
   172  	if duplicate {
   173  		// try to get the manifest
   174  		m, err := manifest.FindOne(manifest.ById(task.Version))
   175  		if err != nil {
   176  			http.Error(w, fmt.Sprintf("error getting latest manifest for %v: %v", newManifest.ProjectName, err),
   177  				http.StatusBadRequest)
   178  			return
   179  		}
   180  		if m != nil {
   181  			plugin.WriteJSON(w, http.StatusOK, m)
   182  			return
   183  		}
   184  	}
   185  	// no duplicate key error, use the manifest just created.
   186  
   187  	plugin.WriteJSON(w, http.StatusOK, newManifest)
   188  	return
   189  }