github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+incompatible/command/v3/v3_push_command.go (about)

     1  package v3
     2  
     3  import (
     4  	"code.cloudfoundry.org/cli/actor/pushaction"
     5  	"code.cloudfoundry.org/cli/actor/sharedaction"
     6  	"code.cloudfoundry.org/cli/actor/v2action"
     7  	"code.cloudfoundry.org/cli/actor/v3action"
     8  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
     9  	"code.cloudfoundry.org/cli/command"
    10  	"code.cloudfoundry.org/cli/command/flag"
    11  	sharedV2 "code.cloudfoundry.org/cli/command/v2/shared"
    12  	"code.cloudfoundry.org/cli/command/v3/shared"
    13  	"code.cloudfoundry.org/cli/util/progressbar"
    14  
    15  	log "github.com/sirupsen/logrus"
    16  )
    17  
    18  //go:generate counterfeiter . ProgressBar
    19  
    20  type ProgressBar interface {
    21  	pushaction.ProgressBar
    22  	Complete()
    23  	Ready()
    24  }
    25  
    26  //go:generate counterfeiter . V3PushActor
    27  
    28  type V3PushActor interface {
    29  	Actualize(state pushaction.PushState, progressBar pushaction.ProgressBar) (<-chan pushaction.PushState, <-chan pushaction.Event, <-chan pushaction.Warnings, <-chan error)
    30  	Conceptualize(setting pushaction.CommandLineSettings, spaceGUID string) ([]pushaction.PushState, pushaction.Warnings, error)
    31  }
    32  
    33  //go:generate counterfeiter . V3PushVersionActor
    34  
    35  type V3PushVersionActor interface {
    36  	CloudControllerAPIVersion() string
    37  }
    38  
    39  type V3PushCommand struct {
    40  	RequiredArgs flag.AppName `positional-args:"yes"`
    41  	Buildpacks   []string     `short:"b" description:"Custom buildpack by name (e.g. my-buildpack) or Git URL (e.g. 'https://github.com/cloudfoundry/java-buildpack.git') or Git URL with a branch or tag (e.g. 'https://github.com/cloudfoundry/java-buildpack.git#v3.3.0' for 'v3.3.0' tag). To use built-in buildpacks only, specify 'default' or 'null'"`
    42  	// Command flag.Command
    43  	// Domain string
    44  	DockerImage    flag.DockerImage `long:"docker-image" short:"o" description:"Docker image to use (e.g. user/docker-image-name)"`
    45  	DockerUsername string           `long:"docker-username" description:"Repository username; used with password from environment variable CF_DOCKER_PASSWORD"`
    46  	// DropletPath flag.PathWithExistenceCheck
    47  	// PathToManifest flag.PathWithExistenceCheck
    48  	// HealthCheckType flag.HealthCheckType
    49  	// Hostname string
    50  	// Instances flag.Instances
    51  	// DiskQuota           flag.Megabytes
    52  	// Memory              flag.Megabytes
    53  	// NoHostname          bool
    54  	// NoManifest          bool
    55  	NoRoute bool                        `long:"no-route" description:"Do not map a route to this app"`
    56  	NoStart bool                        `long:"no-start" description:"Do not stage and start the app after pushing"`
    57  	AppPath flag.PathWithExistenceCheck `short:"p" description:"Path to app directory or to a zip file of the contents of the app directory"`
    58  	// RandomRoute         bool
    59  	// RoutePath           flag.RoutePath
    60  	// StackName           string
    61  	// VarsFilePaths []flag.PathWithExistenceCheck
    62  	// Vars []template.VarKV
    63  	// HealthCheckTimeout int
    64  	dockerPassword      interface{} `environmentName:"CF_DOCKER_PASSWORD" environmentDescription:"Password used for private docker repository"`
    65  	usage               interface{} `usage:"cf v3-push APP_NAME [-b BUILDPACK]... [-p APP_PATH] [--no-route] [--no-start]\n   cf v3-push APP_NAME --docker-image [REGISTRY_HOST:PORT/]IMAGE[:TAG] [--docker-username USERNAME] [--no-route] [--no-start]"`
    66  	envCFStagingTimeout interface{} `environmentName:"CF_STAGING_TIMEOUT" environmentDescription:"Max wait time for buildpack staging, in minutes" environmentDefault:"15"`
    67  	envCFStartupTimeout interface{} `environmentName:"CF_STARTUP_TIMEOUT" environmentDescription:"Max wait time for app instance startup, in minutes" environmentDefault:"5"`
    68  
    69  	UI                  command.UI
    70  	Config              command.Config
    71  	NOAAClient          v3action.NOAAClient
    72  	Actor               V3PushActor
    73  	VersionActor        V3PushVersionActor
    74  	SharedActor         command.SharedActor
    75  	AppSummaryDisplayer shared.AppSummaryDisplayer
    76  	PackageDisplayer    shared.PackageDisplayer
    77  	ProgressBar         ProgressBar
    78  
    79  	OriginalActor       OriginalV3PushActor
    80  	OriginalV2PushActor OriginalV2PushActor
    81  }
    82  
    83  func (cmd *V3PushCommand) Setup(config command.Config, ui command.UI) error {
    84  	if !config.Experimental() {
    85  		return cmd.OriginalSetup(config, ui)
    86  	}
    87  
    88  	cmd.Config = config
    89  	cmd.UI = ui
    90  	cmd.ProgressBar = progressbar.NewProgressBar()
    91  
    92  	sharedActor := sharedaction.NewActor(config)
    93  	cmd.SharedActor = sharedActor
    94  
    95  	ccClient, uaaClient, err := shared.NewClients(config, ui, true)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	v3Actor := v3action.NewActor(ccClient, config, sharedActor, uaaClient)
   100  	cmd.VersionActor = v3Actor
   101  
   102  	ccClientV2, uaaClientV2, err := sharedV2.NewClients(config, ui, true)
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	v2Actor := v2action.NewActor(ccClientV2, uaaClientV2, config)
   108  	cmd.Actor = pushaction.NewActor(v2Actor, v3Actor, sharedActor)
   109  
   110  	return nil
   111  }
   112  
   113  func (cmd V3PushCommand) Execute(args []string) error {
   114  	if !cmd.Config.Experimental() {
   115  		return cmd.OriginalExecute(args)
   116  	}
   117  
   118  	err := command.MinimumAPIVersionCheck(cmd.VersionActor.CloudControllerAPIVersion(), ccversion.MinVersionV3)
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	cmd.UI.DisplayWarning(command.ExperimentalWarning)
   124  
   125  	err = cmd.SharedActor.CheckTarget(true, true)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	cmd.UI.DisplayText("Getting app info...")
   131  
   132  	log.Info("generating the app state")
   133  	pushState, warnings, err := cmd.Actor.Conceptualize(pushaction.CommandLineSettings{
   134  		Buildpacks:      cmd.Buildpacks,
   135  		Name:            cmd.RequiredArgs.AppName,
   136  		ProvidedAppPath: string(cmd.AppPath),
   137  	}, cmd.Config.TargetedSpace().GUID)
   138  	cmd.UI.DisplayWarnings(warnings)
   139  	if err != nil {
   140  		return err
   141  	}
   142  	log.WithField("number of states", len(pushState)).Debug("completed generating state")
   143  
   144  	for _, state := range pushState {
   145  		log.WithField("app_name", state.Application.Name).Info("actualizing")
   146  		stateStream, eventStream, warningsStream, errorStream := cmd.Actor.Actualize(state, cmd.ProgressBar)
   147  		_, err = cmd.processApplyStreams(state.Application.Name, stateStream, eventStream, warningsStream, errorStream)
   148  		if err != nil {
   149  			return err
   150  		}
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  func (cmd V3PushCommand) processApplyStreams(
   157  	appName string,
   158  	stateStream <-chan pushaction.PushState,
   159  	eventStream <-chan pushaction.Event,
   160  	warningsStream <-chan pushaction.Warnings,
   161  	errorStream <-chan error,
   162  ) (pushaction.PushState, error) {
   163  	var stateClosed, eventClosed, warningsClosed, complete bool
   164  	var updateState pushaction.PushState
   165  
   166  	for {
   167  		select {
   168  		case state, ok := <-stateStream:
   169  			if !ok {
   170  				log.Debug("processing config stream closed")
   171  				stateClosed = true
   172  				break
   173  			}
   174  			updateState = state
   175  			log.Debugf("updated config received: %#v", updateState)
   176  		case event, ok := <-eventStream:
   177  			if !ok {
   178  				log.Debug("processing event stream closed")
   179  				eventClosed = true
   180  				break
   181  			}
   182  			complete = cmd.processEvent(appName, event)
   183  		case warnings, ok := <-warningsStream:
   184  			if !ok {
   185  				log.Debug("processing warnings stream closed")
   186  				warningsClosed = true
   187  				break
   188  			}
   189  			cmd.UI.DisplayWarnings(warnings)
   190  		case err, ok := <-errorStream:
   191  			if !ok {
   192  				log.Debug("processing error stream closed")
   193  				warningsClosed = true
   194  				break
   195  			}
   196  			return pushaction.PushState{}, err
   197  		}
   198  
   199  		if stateClosed && eventClosed && warningsClosed && complete {
   200  			log.Debug("breaking apply display loop")
   201  			break
   202  		}
   203  	}
   204  
   205  	return updateState, nil
   206  }
   207  
   208  func (cmd V3PushCommand) processEvent(appName string, event pushaction.Event) bool {
   209  	log.Infoln("received apply event:", event)
   210  
   211  	switch event {
   212  	case pushaction.CreatedApplication:
   213  		cmd.UI.DisplayTextWithFlavor("Creating app {{.AppName}}...", map[string]interface{}{
   214  			"AppName": appName,
   215  		})
   216  	case pushaction.SkipingApplicationCreation:
   217  		cmd.UI.DisplayTextWithFlavor("Updating app {{.AppName}}...", map[string]interface{}{
   218  			"AppName": appName,
   219  		})
   220  	case pushaction.Complete:
   221  		return true
   222  	default:
   223  		log.WithField("event", event).Debug("ignoring event")
   224  	}
   225  	return false
   226  }