github.com/Thanhphan1147/cloudfoundry-cli@v7.1.0+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) HasMultipleBuildpacks() 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  		config := ApplicationConfig{
    60  			NoRoute: app.NoRoute,
    61  		}
    62  
    63  		if app.DropletPath != "" {
    64  			absPath, err := filepath.EvalSymlinks(app.DropletPath)
    65  			if err != nil {
    66  				return nil, nil, err
    67  			}
    68  			config.DropletPath = absPath
    69  		} else {
    70  			absPath, err := filepath.EvalSymlinks(app.Path)
    71  			if err != nil {
    72  				return nil, nil, err
    73  			}
    74  			config.Path = absPath
    75  		}
    76  
    77  		log.Infoln("searching for app", app.Name)
    78  		found, constructedApp, v2Warnings, err := actor.FindOrReturnPartialApp(app.Name, spaceGUID)
    79  		warnings = append(warnings, v2Warnings...)
    80  		if err != nil {
    81  			log.Errorln("app lookup:", err)
    82  			return nil, warnings, err
    83  		}
    84  
    85  		if found {
    86  			var configWarnings v2action.Warnings
    87  			config, configWarnings, err = actor.configureExistingApp(config, app, constructedApp)
    88  			warnings = append(warnings, configWarnings...)
    89  			if err != nil {
    90  				log.Errorln("configuring existing app:", err)
    91  				return nil, warnings, err
    92  			}
    93  		} else {
    94  			log.Debug("using empty app as base")
    95  			config.DesiredApplication = constructedApp
    96  		}
    97  		config.DesiredApplication = actor.overrideApplicationProperties(config.DesiredApplication, app, noStart)
    98  
    99  		var stackWarnings Warnings
   100  		config.DesiredApplication, stackWarnings, err = actor.overrideStack(config.DesiredApplication, app)
   101  		warnings = append(warnings, stackWarnings...)
   102  		if err != nil {
   103  			return nil, warnings, err
   104  		}
   105  		log.Debugln("post overriding config:", config.DesiredApplication)
   106  
   107  		var serviceWarnings Warnings
   108  		config.DesiredServices, serviceWarnings, err = actor.getDesiredServices(config.CurrentServices, app.Services, spaceGUID)
   109  		warnings = append(warnings, serviceWarnings...)
   110  		if err != nil {
   111  			log.Errorln("getting services:", err)
   112  			return nil, warnings, err
   113  		}
   114  
   115  		if !config.NoRoute {
   116  			var routeWarnings Warnings
   117  			config, routeWarnings, err = actor.configureRoutes(app, orgGUID, spaceGUID, config)
   118  			warnings = append(warnings, routeWarnings...)
   119  			if err != nil {
   120  				log.Errorln("determining routes:", err)
   121  				return nil, warnings, err
   122  			}
   123  		}
   124  
   125  		if app.DockerImage == "" && app.DropletPath == "" {
   126  			config, err = actor.configureResources(config)
   127  			if err != nil {
   128  				log.Errorln("configuring resources", err)
   129  				return nil, warnings, err
   130  			}
   131  		}
   132  
   133  		configs = append(configs, config)
   134  	}
   135  
   136  	return configs, warnings, nil
   137  }
   138  
   139  func (actor Actor) configureRoutes(manifestApp manifest.Application, orgGUID string, spaceGUID string, config ApplicationConfig) (ApplicationConfig, Warnings, error) {
   140  	switch {
   141  	case len(manifestApp.Routes) > 0: // Routes in manifest mutually exclusive with all other route related fields
   142  		routes, warnings, err := actor.CalculateRoutes(manifestApp.Routes, orgGUID, spaceGUID, config.CurrentRoutes)
   143  		config.DesiredRoutes = routes
   144  		return config, warnings, err
   145  	case len(config.CurrentRoutes) > 0 && (manifestApp.RandomRoute || manifestApp.Domain == ""):
   146  		config.DesiredRoutes = config.CurrentRoutes
   147  		return config, nil, nil
   148  	case manifestApp.RandomRoute:
   149  		// append random route to current route (becomes desired route)
   150  		randomRoute, warnings, err := actor.GenerateRandomRoute(manifestApp, spaceGUID, orgGUID)
   151  		config.DesiredRoutes = append(config.CurrentRoutes, randomRoute)
   152  		return config, warnings, err
   153  	default:
   154  		desiredRoute, warnings, err := actor.GetGeneratedRoute(manifestApp, orgGUID, spaceGUID, config.CurrentRoutes)
   155  		if err != nil {
   156  			log.Errorln("getting default route:", err)
   157  			return config, warnings, err
   158  		}
   159  		config.DesiredRoutes = append(config.CurrentRoutes, desiredRoute)
   160  		return config, warnings, nil
   161  	}
   162  }
   163  
   164  func (actor Actor) getDesiredServices(currentServices map[string]v2action.ServiceInstance, requestedServices []string, spaceGUID string) (map[string]v2action.ServiceInstance, Warnings, error) {
   165  	var warnings Warnings
   166  
   167  	desiredServices := map[string]v2action.ServiceInstance{}
   168  	for name, serviceInstance := range currentServices {
   169  		log.Debugln("adding bound service:", name)
   170  		desiredServices[name] = serviceInstance
   171  	}
   172  
   173  	for _, serviceName := range requestedServices {
   174  		if _, ok := desiredServices[serviceName]; !ok {
   175  			log.Debugln("adding requested service:", serviceName)
   176  			serviceInstance, serviceWarnings, err := actor.V2Actor.GetServiceInstanceByNameAndSpace(serviceName, spaceGUID)
   177  			warnings = append(warnings, serviceWarnings...)
   178  			if err != nil {
   179  				return nil, warnings, err
   180  			}
   181  
   182  			desiredServices[serviceName] = serviceInstance
   183  		}
   184  	}
   185  	return desiredServices, warnings, nil
   186  }
   187  
   188  func (actor Actor) configureExistingApp(config ApplicationConfig, app manifest.Application, foundApp Application) (ApplicationConfig, v2action.Warnings, error) {
   189  	log.Debugln("found app:", foundApp)
   190  	config.CurrentApplication = foundApp
   191  	config.DesiredApplication = foundApp
   192  
   193  	log.Info("looking up application routes")
   194  	routes, warnings, err := actor.V2Actor.GetApplicationRoutes(foundApp.GUID)
   195  	if err != nil {
   196  		log.Errorln("existing routes lookup:", err)
   197  		return config, warnings, err
   198  	}
   199  
   200  	serviceInstances, serviceWarnings, err := actor.V2Actor.GetServiceInstancesByApplication(foundApp.GUID)
   201  	warnings = append(warnings, serviceWarnings...)
   202  	if err != nil {
   203  		log.Errorln("existing services lookup:", err)
   204  		return config, warnings, err
   205  	}
   206  
   207  	nameToService := map[string]v2action.ServiceInstance{}
   208  	for _, serviceInstance := range serviceInstances {
   209  		nameToService[serviceInstance.Name] = serviceInstance
   210  	}
   211  
   212  	config.CurrentRoutes = routes
   213  	config.CurrentServices = nameToService
   214  	return config, warnings, nil
   215  }
   216  
   217  func (actor Actor) configureResources(config ApplicationConfig) (ApplicationConfig, error) {
   218  	info, err := os.Stat(config.Path)
   219  	if err != nil {
   220  		return config, err
   221  	}
   222  
   223  	var resources []sharedaction.Resource
   224  	if info.IsDir() {
   225  		log.WithField("path_to_resources", config.Path).Info("determine directory resources to zip")
   226  		resources, err = actor.SharedActor.GatherDirectoryResources(config.Path)
   227  	} else {
   228  		config.Archive = true
   229  		log.WithField("path_to_resources", config.Path).Info("determine archive resources to zip")
   230  		resources, err = actor.SharedActor.GatherArchiveResources(config.Path)
   231  	}
   232  	if err != nil {
   233  		return config, err
   234  	}
   235  	config.AllResources = actor.ConvertSharedResourcesToV2Resources(resources)
   236  
   237  	log.WithField("number_of_files", len(resources)).Debug("completed file scan")
   238  
   239  	return config, nil
   240  }
   241  
   242  func (Actor) overrideApplicationProperties(application Application, manifest manifest.Application, noStart bool) Application {
   243  	if manifest.Buildpack.IsSet {
   244  		application.Buildpacks = []string{}
   245  		if len(manifest.Buildpack.Value) > 0 {
   246  			application.Buildpacks = append(application.Buildpacks, manifest.Buildpack.Value)
   247  		}
   248  	}
   249  
   250  	if manifest.Buildpacks != nil {
   251  		application.Buildpacks = append([]string{}, manifest.Buildpacks...)
   252  	}
   253  
   254  	if manifest.Command.IsSet {
   255  		application.Command = manifest.Command
   256  	}
   257  
   258  	if manifest.DockerImage != "" {
   259  		application.DockerImage = manifest.DockerImage
   260  		if manifest.DockerUsername != "" {
   261  			application.DockerCredentials.Username = manifest.DockerUsername
   262  			application.DockerCredentials.Password = manifest.DockerPassword
   263  		}
   264  	}
   265  
   266  	if manifest.DiskQuota.IsSet {
   267  		application.DiskQuota = manifest.DiskQuota
   268  	}
   269  
   270  	if manifest.Memory.IsSet {
   271  		application.Memory = manifest.Memory
   272  	}
   273  
   274  	if manifest.HealthCheckTimeout != 0 {
   275  		application.HealthCheckTimeout = manifest.HealthCheckTimeout
   276  	}
   277  
   278  	if manifest.HealthCheckType != "" {
   279  		application.HealthCheckType = constant.ApplicationHealthCheckType(manifest.HealthCheckType)
   280  		application.HealthCheckHTTPEndpoint = manifest.HealthCheckHTTPEndpoint
   281  
   282  		if application.HealthCheckType == constant.ApplicationHealthCheckHTTP && application.HealthCheckHTTPEndpoint == "" {
   283  			application.HealthCheckHTTPEndpoint = "/"
   284  		}
   285  	}
   286  
   287  	if manifest.Instances.IsSet {
   288  		application.Instances = manifest.Instances
   289  	}
   290  
   291  	if noStart {
   292  		application.State = constant.ApplicationStopped
   293  	}
   294  
   295  	if len(manifest.EnvironmentVariables) > 0 {
   296  		if application.EnvironmentVariables == nil {
   297  			application.EnvironmentVariables = manifest.EnvironmentVariables
   298  		} else {
   299  			env := map[string]string{}
   300  			for key, value := range application.EnvironmentVariables {
   301  				env[key] = value
   302  			}
   303  			for key, value := range manifest.EnvironmentVariables {
   304  				env[key] = value
   305  			}
   306  			application.EnvironmentVariables = env
   307  		}
   308  	}
   309  
   310  	log.Debugln("post application override:", application)
   311  
   312  	return application
   313  }
   314  
   315  func (actor Actor) overrideStack(application Application, manifest manifest.Application) (Application, Warnings, error) {
   316  	if manifest.StackName == "" {
   317  		return application, nil, nil
   318  	}
   319  	stack, warnings, err := actor.V2Actor.GetStackByName(manifest.StackName)
   320  	application.SetStack(stack)
   321  	return application, Warnings(warnings), err
   322  }