github.com/cloudfoundry/cli@v7.1.0+incompatible/actor/v7action/build.go (about)

     1  package v7action
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  	"time"
     7  
     8  	"code.cloudfoundry.org/cli/actor/actionerror"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    11  	"code.cloudfoundry.org/cli/resources"
    12  
    13  	log "github.com/sirupsen/logrus"
    14  )
    15  
    16  type Build struct {
    17  	GUID string
    18  }
    19  
    20  func (actor Actor) StagePackage(packageGUID, appName, spaceGUID string) (<-chan resources.Droplet, <-chan Warnings, <-chan error) {
    21  	dropletStream := make(chan resources.Droplet)
    22  	warningsStream := make(chan Warnings)
    23  	errorStream := make(chan error)
    24  	go func() {
    25  		defer close(dropletStream)
    26  		defer close(warningsStream)
    27  		defer close(errorStream)
    28  
    29  		apps, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{appName}, spaceGUID)
    30  		warningsStream <- warnings
    31  		if err != nil {
    32  			if _, ok := err.(actionerror.ApplicationsNotFoundError); ok {
    33  				err = actionerror.ApplicationNotFoundError{Name: appName}
    34  			}
    35  			errorStream <- err
    36  			return
    37  		}
    38  		app := apps[0]
    39  
    40  		pkgs, allWarnings, err := actor.CloudControllerClient.GetPackages(ccv3.Query{
    41  			Key: ccv3.AppGUIDFilter, Values: []string{app.GUID},
    42  		})
    43  		warningsStream <- Warnings(allWarnings)
    44  		if err != nil {
    45  			errorStream <- err
    46  			return
    47  		}
    48  
    49  		if !packageInPackages(packageGUID, pkgs) {
    50  			err = actionerror.PackageNotFoundInAppError{GUID: packageGUID, AppName: appName}
    51  			errorStream <- err
    52  			return
    53  		}
    54  
    55  		build := ccv3.Build{PackageGUID: packageGUID}
    56  		build, allWarnings, err = actor.CloudControllerClient.CreateBuild(build)
    57  		warningsStream <- Warnings(allWarnings)
    58  
    59  		if err != nil {
    60  			errorStream <- err
    61  			return
    62  		}
    63  
    64  		timer := actor.Clock.NewTimer(time.Millisecond)
    65  		defer timer.Stop()
    66  		timeout := actor.Clock.After(actor.Config.StagingTimeout())
    67  
    68  		for {
    69  			select {
    70  			case <-timeout:
    71  				errorStream <- actionerror.StagingTimeoutError{AppName: appName, Timeout: actor.Config.StagingTimeout()}
    72  				return
    73  			case <-timer.C():
    74  				var warnings ccv3.Warnings
    75  				build, warnings, err = actor.CloudControllerClient.GetBuild(build.GUID)
    76  				warningsStream <- Warnings(warnings)
    77  				if err != nil {
    78  					errorStream <- err
    79  					return
    80  				}
    81  
    82  				switch build.State {
    83  				case constant.BuildFailed:
    84  					if strings.Contains(build.Error, "NoAppDetectedError") {
    85  						errorStream <- actionerror.StagingFailedNoAppDetectedError{Reason: build.Error}
    86  					} else {
    87  						errorStream <- actionerror.StagingFailedError{Reason: build.Error}
    88  					}
    89  					return
    90  				case constant.BuildStaging:
    91  					timer.Reset(actor.Config.PollingInterval())
    92  				default:
    93  
    94  					//TODO: uncomment after #150569020
    95  					// droplet, warnings, err := actor.CloudControllerClient.GetDroplet(build.DropletGUID)
    96  					// warningsStream <- Warnings(warnings)
    97  					// if err != nil {
    98  					// 	errorStream <- err
    99  					// 	return
   100  					// }
   101  
   102  					droplet := resources.Droplet{
   103  						GUID:      build.DropletGUID,
   104  						State:     constant.DropletState(build.State),
   105  						CreatedAt: build.CreatedAt,
   106  					}
   107  
   108  					dropletStream <- droplet
   109  					return
   110  				}
   111  			}
   112  		}
   113  	}()
   114  
   115  	return dropletStream, warningsStream, errorStream
   116  }
   117  
   118  func (actor Actor) StageApplicationPackage(packageGUID string) (Build, Warnings, error) {
   119  	var allWarnings Warnings
   120  
   121  	build := ccv3.Build{PackageGUID: packageGUID}
   122  	build, warnings, err := actor.CloudControllerClient.CreateBuild(build)
   123  	log.Debug("created build")
   124  	allWarnings = append(allWarnings, warnings...)
   125  	if err != nil {
   126  		return Build{}, allWarnings, err
   127  	}
   128  
   129  	log.Debug("no errors creating build")
   130  	return Build{GUID: build.GUID}, allWarnings, nil
   131  }
   132  
   133  func (actor Actor) PollBuild(buildGUID string, appName string) (resources.Droplet, Warnings, error) {
   134  	var allWarnings Warnings
   135  
   136  	timeout := actor.Clock.After(actor.Config.StagingTimeout())
   137  	interval := actor.Clock.NewTimer(time.Millisecond)
   138  
   139  	for {
   140  		select {
   141  		case <-interval.C():
   142  			build, warnings, err := actor.CloudControllerClient.GetBuild(buildGUID)
   143  			allWarnings = append(allWarnings, warnings...)
   144  			if err != nil {
   145  				return resources.Droplet{}, allWarnings, err
   146  			}
   147  
   148  			switch build.State {
   149  			case constant.BuildFailed:
   150  				return resources.Droplet{}, allWarnings, errors.New(build.Error)
   151  
   152  			case constant.BuildStaged:
   153  				droplet, warnings, err := actor.CloudControllerClient.GetDroplet(build.DropletGUID)
   154  				allWarnings = append(allWarnings, warnings...)
   155  				if err != nil {
   156  					return resources.Droplet{}, allWarnings, err
   157  				}
   158  
   159  				return resources.Droplet{
   160  					GUID:      droplet.GUID,
   161  					State:     droplet.State,
   162  					CreatedAt: droplet.CreatedAt,
   163  				}, allWarnings, nil
   164  			}
   165  
   166  			interval.Reset(actor.Config.PollingInterval())
   167  
   168  		case <-timeout:
   169  			return resources.Droplet{}, allWarnings, actionerror.StagingTimeoutError{AppName: appName, Timeout: actor.Config.StagingTimeout()}
   170  		}
   171  	}
   172  }
   173  
   174  func packageInPackages(targetPkgGUID string, pkgs []ccv3.Package) bool {
   175  	for i := range pkgs {
   176  		if pkgs[i].GUID == targetPkgGUID {
   177  			return true
   178  		}
   179  	}
   180  	return false
   181  }