code.cloudfoundry.org/cli@v7.1.0+incompatible/actor/pushaction/apply.go (about)

     1  package pushaction
     2  
     3  import (
     4  	"os"
     5  
     6  	"code.cloudfoundry.org/cli/actor/actionerror"
     7  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     8  
     9  	log "github.com/sirupsen/logrus"
    10  )
    11  
    12  const PushRetries = 3
    13  
    14  // Apply use the V2 API to create/update the application settings and
    15  // eventually uploads the application bits.
    16  //
    17  // If multiple buildpacks are being applied to the application, the V3 API is
    18  // used to set those buildpacks.
    19  func (actor Actor) Apply(config ApplicationConfig, progressBar ProgressBar) (<-chan ApplicationConfig, <-chan Event, <-chan Warnings, <-chan error) {
    20  	configStream := make(chan ApplicationConfig)
    21  	eventStream := make(chan Event)
    22  	warningsStream := make(chan Warnings)
    23  	errorStream := make(chan error)
    24  
    25  	go func() {
    26  		log.Debug("starting apply go routine")
    27  		defer close(configStream)
    28  		defer close(eventStream)
    29  		defer close(warningsStream)
    30  		defer close(errorStream)
    31  
    32  		var event Event
    33  		var warnings Warnings
    34  		var err error
    35  
    36  		eventStream <- SettingUpApplication
    37  		if config.UpdatingApplication() {
    38  			config, event, warnings, err = actor.UpdateApplication(config)
    39  		} else {
    40  			config, event, warnings, err = actor.CreateApplication(config)
    41  		}
    42  
    43  		warningsStream <- warnings
    44  		if err != nil {
    45  			errorStream <- err
    46  			return
    47  		}
    48  		eventStream <- event
    49  		log.Debugf("desired application: %#v", config.DesiredApplication)
    50  
    51  		if config.NoRoute {
    52  			if len(config.CurrentRoutes) > 0 {
    53  				eventStream <- UnmappingRoutes
    54  				config, warnings, err = actor.UnmapRoutes(config)
    55  				warningsStream <- warnings
    56  				if err != nil {
    57  					errorStream <- err
    58  					return
    59  				}
    60  			}
    61  		} else {
    62  			eventStream <- CreatingAndMappingRoutes
    63  
    64  			var createdRoutes bool
    65  			config, createdRoutes, warnings, err = actor.CreateRoutes(config)
    66  			warningsStream <- warnings
    67  			if err != nil {
    68  				errorStream <- err
    69  				return
    70  			}
    71  			if createdRoutes {
    72  				log.Debugf("updated desired routes: %#v", config.DesiredRoutes)
    73  				eventStream <- CreatedRoutes
    74  			}
    75  
    76  			var boundRoutes bool
    77  			config, boundRoutes, warnings, err = actor.MapRoutes(config)
    78  			warningsStream <- warnings
    79  			if err != nil {
    80  				errorStream <- err
    81  				return
    82  			}
    83  			if boundRoutes {
    84  				log.Debugf("updated desired routes: %#v", config.DesiredRoutes)
    85  				eventStream <- BoundRoutes
    86  			}
    87  		}
    88  
    89  		if len(config.CurrentServices) != len(config.DesiredServices) {
    90  			eventStream <- ConfiguringServices
    91  			config, _, warnings, err = actor.BindServices(config)
    92  			warningsStream <- warnings
    93  			if err != nil {
    94  				errorStream <- err
    95  				return
    96  			}
    97  
    98  			log.Debugf("bound desired services: %#v", config.DesiredServices)
    99  			eventStream <- BoundServices
   100  		}
   101  
   102  		if config.DropletPath != "" {
   103  			for count := 0; count < PushRetries; count++ {
   104  				warnings, err = actor.UploadDroplet(config, config.DropletPath, progressBar, eventStream)
   105  				warningsStream <- warnings
   106  				if _, ok := err.(ccerror.PipeSeekError); ok {
   107  					eventStream <- RetryUpload
   108  				} else {
   109  					break
   110  				}
   111  			}
   112  
   113  			if err != nil {
   114  				if e, ok := err.(ccerror.PipeSeekError); ok {
   115  					errorStream <- actionerror.UploadFailedError{Err: e.Err}
   116  				} else {
   117  					errorStream <- err
   118  				}
   119  				return
   120  			}
   121  		} else if config.DesiredApplication.DockerImage == "" {
   122  			eventStream <- ResourceMatching
   123  			config, warnings = actor.SetMatchedResources(config)
   124  			warningsStream <- warnings
   125  
   126  			if len(config.UnmatchedResources) > 0 {
   127  				var archivePath string
   128  				archivePath, err = actor.CreateArchive(config)
   129  				if err != nil {
   130  					errorStream <- err
   131  					os.RemoveAll(archivePath)
   132  					return
   133  				}
   134  				eventStream <- CreatingArchive
   135  				defer os.RemoveAll(archivePath)
   136  
   137  				for count := 0; count < PushRetries; count++ {
   138  					warnings, err = actor.UploadPackageWithArchive(config, archivePath, progressBar, eventStream)
   139  					warningsStream <- warnings
   140  					if _, ok := err.(ccerror.PipeSeekError); ok {
   141  						eventStream <- RetryUpload
   142  					} else {
   143  						break
   144  					}
   145  				}
   146  
   147  				if err != nil {
   148  					if e, ok := err.(ccerror.PipeSeekError); ok {
   149  						errorStream <- actionerror.UploadFailedError{Err: e.Err}
   150  					} else {
   151  						errorStream <- err
   152  					}
   153  					return
   154  				}
   155  			} else {
   156  				eventStream <- UploadingApplication
   157  				warnings, err = actor.UploadPackage(config)
   158  				warningsStream <- warnings
   159  				if err != nil {
   160  					errorStream <- err
   161  					return
   162  				}
   163  			}
   164  		} else {
   165  			log.WithField("docker_image", config.DesiredApplication.DockerImage).Debug("skipping file upload")
   166  		}
   167  
   168  		configStream <- config
   169  
   170  		log.Debug("completed apply")
   171  		eventStream <- Complete
   172  	}()
   173  
   174  	return configStream, eventStream, warningsStream, errorStream
   175  }