github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+incompatible/actor/pushaction/application_config.go (about)

     1  package pushaction
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  
     7  	"code.cloudfoundry.org/cli/actor/sharedaction"
     8  	"code.cloudfoundry.org/cli/actor/v2action"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant"
    10  	"code.cloudfoundry.org/cli/util/manifest"
    11  	log "github.com/sirupsen/logrus"
    12  )
    13  
    14  type ApplicationConfig struct {
    15  	CurrentApplication Application
    16  	DesiredApplication Application
    17  
    18  	CurrentRoutes []v2action.Route
    19  	DesiredRoutes []v2action.Route
    20  	NoRoute       bool
    21  
    22  	CurrentServices map[string]v2action.ServiceInstance
    23  	DesiredServices map[string]v2action.ServiceInstance
    24  
    25  	AllResources       []v2action.Resource
    26  	MatchedResources   []v2action.Resource
    27  	UnmatchedResources []v2action.Resource
    28  	Archive            bool
    29  	Path               string
    30  	DropletPath        string
    31  }
    32  
    33  func (config ApplicationConfig) CreatingApplication() bool {
    34  	return config.CurrentApplication.GUID == ""
    35  }
    36  
    37  func (config ApplicationConfig) UpdatingApplication() bool {
    38  	return !config.CreatingApplication()
    39  }
    40  
    41  func (config ApplicationConfig) HasV3Buildpacks() bool {
    42  	return len(config.DesiredApplication.Buildpacks) > 1
    43  }
    44  
    45  // ConvertToApplicationConfigs converts a set of application manifests into an
    46  // application configs. These configs reflect the current and desired states of
    47  // the application - providing details required by the Apply function to
    48  // proceed.
    49  //
    50  // The V2 Actor is primarily used to determine all but multiple buildpack
    51  // information. Only then is the V3 Actor used to gather the multiple
    52  // buildpacks.
    53  func (actor Actor) ConvertToApplicationConfigs(orgGUID string, spaceGUID string, noStart bool, apps []manifest.Application) ([]ApplicationConfig, Warnings, error) {
    54  	var configs []ApplicationConfig
    55  	var warnings Warnings
    56  
    57  	log.Infof("iterating through %d app configuration(s)", len(apps))
    58  	for _, app := range apps {
    59  
    60  		var (
    61  			config  ApplicationConfig
    62  			absPath string
    63  			err     error
    64  		)
    65  		if app.DropletPath != "" {
    66  			absPath, err = filepath.EvalSymlinks(app.DropletPath)
    67  			if err != nil {
    68  				return nil, nil, err
    69  			}
    70  			config = ApplicationConfig{
    71  				DropletPath: absPath,
    72  				NoRoute:     app.NoRoute,
    73  			}
    74  		} else {
    75  			absPath, err = filepath.EvalSymlinks(app.Path)
    76  			if err != nil {
    77  				return nil, nil, err
    78  			}
    79  			config = ApplicationConfig{
    80  				Path:    absPath,
    81  				NoRoute: app.NoRoute,
    82  			}
    83  		}
    84  
    85  		log.Infoln("searching for app", app.Name)
    86  		found, constructedApp, v2Warnings, err := actor.FindOrReturnPartialApp(app.Name, spaceGUID)
    87  		warnings = append(warnings, v2Warnings...)
    88  		if err != nil {
    89  			log.Errorln("app lookup:", err)
    90  			return nil, warnings, err
    91  		}
    92  
    93  		if found {
    94  			var configWarnings v2action.Warnings
    95  			config, configWarnings, err = actor.configureExistingApp(config, app, constructedApp)
    96  			warnings = append(warnings, configWarnings...)
    97  			if err != nil {
    98  				log.Errorln("configuring existing app:", err)
    99  				return nil, warnings, err
   100  			}
   101  		} else {
   102  			log.Debug("using empty app as base")
   103  			config.DesiredApplication = constructedApp
   104  		}
   105  		config.DesiredApplication = actor.overrideApplicationProperties(config.DesiredApplication, app, noStart)
   106  
   107  		var stackWarnings Warnings
   108  		config.DesiredApplication, stackWarnings, err = actor.overrideStack(config.DesiredApplication, app)
   109  		warnings = append(warnings, stackWarnings...)
   110  		if err != nil {
   111  			return nil, warnings, err
   112  		}
   113  		log.Debugln("post overriding config:", config.DesiredApplication)
   114  
   115  		var serviceWarnings Warnings
   116  		config.DesiredServices, serviceWarnings, err = actor.getDesiredServices(config.CurrentServices, app.Services, spaceGUID)
   117  		warnings = append(warnings, serviceWarnings...)
   118  		if err != nil {
   119  			log.Errorln("getting services:", err)
   120  			return nil, warnings, err
   121  		}
   122  
   123  		if !config.NoRoute {
   124  			var routeWarnings Warnings
   125  			config, routeWarnings, err = actor.configureRoutes(app, orgGUID, spaceGUID, config)
   126  			warnings = append(warnings, routeWarnings...)
   127  			if err != nil {
   128  				log.Errorln("determining routes:", err)
   129  				return nil, warnings, err
   130  			}
   131  		}
   132  
   133  		if app.DockerImage == "" && app.DropletPath == "" {
   134  			config, err = actor.configureResources(config)
   135  			if err != nil {
   136  				log.Errorln("configuring resources", err)
   137  				return nil, warnings, err
   138  			}
   139  		}
   140  
   141  		configs = append(configs, config)
   142  	}
   143  
   144  	return configs, warnings, nil
   145  }
   146  
   147  func (actor Actor) configureRoutes(manifestApp manifest.Application, orgGUID string, spaceGUID string, config ApplicationConfig) (ApplicationConfig, Warnings, error) {
   148  	switch {
   149  	case len(manifestApp.Routes) > 0: // Routes in manifest mutually exclusive with all other route related fields
   150  		routes, warnings, err := actor.CalculateRoutes(manifestApp.Routes, orgGUID, spaceGUID, config.CurrentRoutes)
   151  		config.DesiredRoutes = routes
   152  		return config, warnings, err
   153  	case len(config.CurrentRoutes) > 0 && (manifestApp.RandomRoute || manifestApp.Domain == ""):
   154  		config.DesiredRoutes = config.CurrentRoutes
   155  		return config, nil, nil
   156  	case manifestApp.RandomRoute:
   157  		// append random route to current route (becomes desired route)
   158  		randomRoute, warnings, err := actor.GenerateRandomRoute(manifestApp, spaceGUID, orgGUID)
   159  		config.DesiredRoutes = append(config.CurrentRoutes, randomRoute)
   160  		return config, warnings, err
   161  	default:
   162  		desiredRoute, warnings, err := actor.GetGeneratedRoute(manifestApp, orgGUID, spaceGUID, config.CurrentRoutes)
   163  		if err != nil {
   164  			log.Errorln("getting default route:", err)
   165  			return config, warnings, err
   166  		}
   167  		config.DesiredRoutes = append(config.CurrentRoutes, desiredRoute)
   168  		return config, warnings, nil
   169  	}
   170  }
   171  
   172  func (actor Actor) getDesiredServices(currentServices map[string]v2action.ServiceInstance, requestedServices []string, spaceGUID string) (map[string]v2action.ServiceInstance, Warnings, error) {
   173  	var warnings Warnings
   174  
   175  	desiredServices := map[string]v2action.ServiceInstance{}
   176  	for name, serviceInstance := range currentServices {
   177  		log.Debugln("adding bound service:", name)
   178  		desiredServices[name] = serviceInstance
   179  	}
   180  
   181  	for _, serviceName := range requestedServices {
   182  		if _, ok := desiredServices[serviceName]; !ok {
   183  			log.Debugln("adding requested service:", serviceName)
   184  			serviceInstance, serviceWarnings, err := actor.V2Actor.GetServiceInstanceByNameAndSpace(serviceName, spaceGUID)
   185  			warnings = append(warnings, serviceWarnings...)
   186  			if err != nil {
   187  				return nil, warnings, err
   188  			}
   189  
   190  			desiredServices[serviceName] = serviceInstance
   191  		}
   192  	}
   193  	return desiredServices, warnings, nil
   194  }
   195  
   196  func (actor Actor) configureExistingApp(config ApplicationConfig, app manifest.Application, foundApp Application) (ApplicationConfig, v2action.Warnings, error) {
   197  	log.Debugln("found app:", foundApp)
   198  	config.CurrentApplication = foundApp
   199  	config.DesiredApplication = foundApp
   200  
   201  	log.Info("looking up application routes")
   202  	routes, warnings, err := actor.V2Actor.GetApplicationRoutes(foundApp.GUID)
   203  	if err != nil {
   204  		log.Errorln("existing routes lookup:", err)
   205  		return config, warnings, err
   206  	}
   207  
   208  	serviceInstances, serviceWarnings, err := actor.V2Actor.GetServiceInstancesByApplication(foundApp.GUID)
   209  	warnings = append(warnings, serviceWarnings...)
   210  	if err != nil {
   211  		log.Errorln("existing services lookup:", err)
   212  		return config, warnings, err
   213  	}
   214  
   215  	nameToService := map[string]v2action.ServiceInstance{}
   216  	for _, serviceInstance := range serviceInstances {
   217  		nameToService[serviceInstance.Name] = serviceInstance
   218  	}
   219  
   220  	config.CurrentRoutes = routes
   221  	config.CurrentServices = nameToService
   222  	return config, warnings, nil
   223  }
   224  
   225  func (actor Actor) configureResources(config ApplicationConfig) (ApplicationConfig, error) {
   226  	info, err := os.Stat(config.Path)
   227  	if err != nil {
   228  		return config, err
   229  	}
   230  
   231  	var resources []sharedaction.Resource
   232  	if info.IsDir() {
   233  		log.WithField("path_to_resources", config.Path).Info("determine directory resources to zip")
   234  		resources, err = actor.SharedActor.GatherDirectoryResources(config.Path)
   235  	} else {
   236  		config.Archive = true
   237  		log.WithField("path_to_resources", config.Path).Info("determine archive resources to zip")
   238  		resources, err = actor.SharedActor.GatherArchiveResources(config.Path)
   239  	}
   240  	if err != nil {
   241  		return config, err
   242  	}
   243  	config.AllResources = actor.ConvertSharedResourcesToV2Resources(resources)
   244  
   245  	log.WithField("number_of_files", len(resources)).Debug("completed file scan")
   246  
   247  	return config, nil
   248  }
   249  
   250  func (Actor) overrideApplicationProperties(application Application, manifest manifest.Application, noStart bool) Application {
   251  
   252  	if manifest.Buildpack.IsSet {
   253  		application.Buildpack = manifest.Buildpack
   254  	}
   255  
   256  	if manifest.Buildpacks != nil {
   257  		application.Buildpacks = []string{}
   258  	}
   259  
   260  	for _, buildpack := range manifest.Buildpacks {
   261  		application.Buildpacks = append(application.Buildpacks, buildpack)
   262  	}
   263  
   264  	if manifest.Command.IsSet {
   265  		application.Command = manifest.Command
   266  	}
   267  	if manifest.DockerImage != "" {
   268  		application.DockerImage = manifest.DockerImage
   269  		if manifest.DockerUsername != "" {
   270  			application.DockerCredentials.Username = manifest.DockerUsername
   271  			application.DockerCredentials.Password = manifest.DockerPassword
   272  		}
   273  	}
   274  
   275  	if manifest.DiskQuota.IsSet {
   276  		application.DiskQuota = manifest.DiskQuota
   277  	}
   278  
   279  	if manifest.Memory.IsSet {
   280  		application.Memory = manifest.Memory
   281  	}
   282  
   283  	if manifest.HealthCheckTimeout != 0 {
   284  		application.HealthCheckTimeout = manifest.HealthCheckTimeout
   285  	}
   286  
   287  	if manifest.HealthCheckType != "" {
   288  		application.HealthCheckType = constant.ApplicationHealthCheckType(manifest.HealthCheckType)
   289  		application.HealthCheckHTTPEndpoint = manifest.HealthCheckHTTPEndpoint
   290  
   291  		if application.HealthCheckType == constant.ApplicationHealthCheckHTTP && application.HealthCheckHTTPEndpoint == "" {
   292  			application.HealthCheckHTTPEndpoint = "/"
   293  		}
   294  	}
   295  
   296  	if manifest.Instances.IsSet {
   297  		application.Instances = manifest.Instances
   298  	}
   299  
   300  	if noStart {
   301  		application.State = constant.ApplicationStopped
   302  	}
   303  
   304  	if len(manifest.EnvironmentVariables) > 0 {
   305  		if application.EnvironmentVariables == nil {
   306  			application.EnvironmentVariables = manifest.EnvironmentVariables
   307  		} else {
   308  			env := map[string]string{}
   309  			for key, value := range application.EnvironmentVariables {
   310  				env[key] = value
   311  			}
   312  			for key, value := range manifest.EnvironmentVariables {
   313  				env[key] = value
   314  			}
   315  			application.EnvironmentVariables = env
   316  		}
   317  	}
   318  
   319  	log.Debugln("post application override:", application)
   320  
   321  	return application
   322  }
   323  
   324  func (actor Actor) overrideStack(application Application, manifest manifest.Application) (Application, Warnings, error) {
   325  	if manifest.StackName == "" {
   326  		return application, nil, nil
   327  	}
   328  	stack, warnings, err := actor.V2Actor.GetStackByName(manifest.StackName)
   329  	application.SetStack(stack)
   330  	return application, Warnings(warnings), err
   331  }