github.com/dcarley/cf-cli@v6.24.1-0.20170220111324-4225ff346898+incompatible/cf/commands/create_app_manifest.go (about)

     1  package commands
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"sort"
     8  
     9  	"code.cloudfoundry.org/cli/cf/flags"
    10  	. "code.cloudfoundry.org/cli/cf/i18n"
    11  
    12  	"code.cloudfoundry.org/cli/cf/api"
    13  	"code.cloudfoundry.org/cli/cf/api/appinstances"
    14  	"code.cloudfoundry.org/cli/cf/api/stacks"
    15  	"code.cloudfoundry.org/cli/cf/commandregistry"
    16  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
    17  	"code.cloudfoundry.org/cli/cf/manifest"
    18  	"code.cloudfoundry.org/cli/cf/models"
    19  	"code.cloudfoundry.org/cli/cf/requirements"
    20  	"code.cloudfoundry.org/cli/cf/terminal"
    21  )
    22  
    23  type CreateAppManifest struct {
    24  	ui               terminal.UI
    25  	config           coreconfig.Reader
    26  	appSummaryRepo   api.AppSummaryRepository
    27  	stackRepo        stacks.StackRepository
    28  	appInstancesRepo appinstances.Repository
    29  	appReq           requirements.ApplicationRequirement
    30  	manifest         manifest.App
    31  }
    32  
    33  func init() {
    34  	commandregistry.Register(&CreateAppManifest{})
    35  }
    36  
    37  func (cmd *CreateAppManifest) MetaData() commandregistry.CommandMetadata {
    38  	fs := make(map[string]flags.FlagSet)
    39  	fs["p"] = &flags.StringFlag{ShortName: "p", Usage: T("Specify a path for file creation. If path not specified, manifest file is created in current working directory.")}
    40  
    41  	return commandregistry.CommandMetadata{
    42  		Name:        "create-app-manifest",
    43  		Description: T("Create an app manifest for an app that has been pushed successfully"),
    44  		Usage: []string{
    45  			T("CF_NAME create-app-manifest APP_NAME [-p /path/to/<app-name>-manifest.yml ]"),
    46  		},
    47  		Flags: fs,
    48  	}
    49  }
    50  
    51  func (cmd *CreateAppManifest) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) {
    52  	if len(fc.Args()) != 1 {
    53  		cmd.ui.Failed(T("Incorrect Usage. Requires APP_NAME as argument\n\n") + commandregistry.Commands.CommandUsage("create-app-manifest"))
    54  		return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 1)
    55  	}
    56  
    57  	cmd.appReq = requirementsFactory.NewApplicationRequirement(fc.Args()[0])
    58  
    59  	reqs := []requirements.Requirement{
    60  		requirementsFactory.NewLoginRequirement(),
    61  		requirementsFactory.NewTargetedSpaceRequirement(),
    62  		cmd.appReq,
    63  	}
    64  
    65  	return reqs, nil
    66  }
    67  
    68  func (cmd *CreateAppManifest) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command {
    69  	cmd.ui = deps.UI
    70  	cmd.config = deps.Config
    71  	cmd.appSummaryRepo = deps.RepoLocator.GetAppSummaryRepository()
    72  	cmd.stackRepo = deps.RepoLocator.GetStackRepository()
    73  	cmd.manifest = deps.AppManifest
    74  	return cmd
    75  }
    76  
    77  func (cmd *CreateAppManifest) Execute(c flags.FlagContext) error {
    78  	application, apiErr := cmd.appSummaryRepo.GetSummary(cmd.appReq.GetApplication().GUID)
    79  	if apiErr != nil {
    80  		return errors.New(T("Error getting application summary: ") + apiErr.Error())
    81  	}
    82  
    83  	stack, err := cmd.stackRepo.FindByGUID(application.StackGUID)
    84  	if err != nil {
    85  		return errors.New(T("Error retrieving stack: ") + err.Error())
    86  	}
    87  
    88  	application.Stack = &stack
    89  
    90  	cmd.ui.Say(T("Creating an app manifest from current settings of app ") + application.Name + " ...")
    91  	cmd.ui.Say("")
    92  
    93  	savePath := "./" + application.Name + "_manifest.yml"
    94  
    95  	if c.String("p") != "" {
    96  		savePath = c.String("p")
    97  	}
    98  
    99  	f, err := os.Create(savePath)
   100  	if err != nil {
   101  		return errors.New(T("Error creating manifest file: ") + err.Error())
   102  	}
   103  	defer f.Close()
   104  
   105  	err = cmd.createManifest(application)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	err = cmd.manifest.Save(f)
   110  	if err != nil {
   111  		return errors.New(T("Error creating manifest file: ") + err.Error())
   112  	}
   113  
   114  	cmd.ui.Ok()
   115  	cmd.ui.Say(T("Manifest file created successfully at ") + savePath)
   116  	cmd.ui.Say("")
   117  	return nil
   118  }
   119  
   120  func (cmd *CreateAppManifest) createManifest(app models.Application) error {
   121  	cmd.manifest.Memory(app.Name, app.Memory)
   122  	cmd.manifest.Instances(app.Name, app.InstanceCount)
   123  	cmd.manifest.Stack(app.Name, app.Stack.Name)
   124  
   125  	if len(app.AppPorts) > 0 {
   126  		cmd.manifest.AppPorts(app.Name, app.AppPorts)
   127  	}
   128  
   129  	if app.Command != "" {
   130  		cmd.manifest.StartCommand(app.Name, app.Command)
   131  	}
   132  
   133  	if app.BuildpackURL != "" {
   134  		cmd.manifest.BuildpackURL(app.Name, app.BuildpackURL)
   135  	}
   136  
   137  	if len(app.Services) > 0 {
   138  		for _, service := range app.Services {
   139  			cmd.manifest.Service(app.Name, service.Name)
   140  		}
   141  	}
   142  
   143  	if app.HealthCheckTimeout > 0 {
   144  		cmd.manifest.HealthCheckTimeout(app.Name, app.HealthCheckTimeout)
   145  	}
   146  
   147  	if app.HealthCheckType != "port" {
   148  		cmd.manifest.HealthCheckType(app.Name, app.HealthCheckType)
   149  	}
   150  
   151  	if app.HealthCheckType == "http" &&
   152  		app.HealthCheckHTTPEndpoint != "" &&
   153  		app.HealthCheckHTTPEndpoint != "/" {
   154  		cmd.manifest.HealthCheckHTTPEndpoint(app.Name, app.HealthCheckHTTPEndpoint)
   155  	}
   156  
   157  	if len(app.EnvironmentVars) > 0 {
   158  		sorted := sortEnvVar(app.EnvironmentVars)
   159  		for _, envVarKey := range sorted {
   160  			switch app.EnvironmentVars[envVarKey].(type) {
   161  			default:
   162  				return errors.New(T("Failed to create manifest, unable to parse environment variable: ") + envVarKey)
   163  			case float64:
   164  				//json.Unmarshal turn all numbers to float64
   165  				value := int(app.EnvironmentVars[envVarKey].(float64))
   166  				cmd.manifest.EnvironmentVars(app.Name, envVarKey, fmt.Sprintf("%d", value))
   167  			case bool:
   168  				cmd.manifest.EnvironmentVars(app.Name, envVarKey, fmt.Sprintf("%t", app.EnvironmentVars[envVarKey].(bool)))
   169  			case string:
   170  				cmd.manifest.EnvironmentVars(app.Name, envVarKey, app.EnvironmentVars[envVarKey].(string))
   171  			}
   172  		}
   173  	}
   174  
   175  	if len(app.Routes) > 0 {
   176  		for i := 0; i < len(app.Routes); i++ {
   177  			cmd.manifest.Route(app.Name, app.Routes[i].Host, app.Routes[i].Domain.Name, app.Routes[i].Path, app.Routes[i].Port)
   178  		}
   179  	}
   180  
   181  	if app.DiskQuota != 0 {
   182  		cmd.manifest.DiskQuota(app.Name, app.DiskQuota)
   183  	}
   184  
   185  	return nil
   186  }
   187  
   188  func sortEnvVar(vars map[string]interface{}) []string {
   189  	var varsAry []string
   190  	for k := range vars {
   191  		varsAry = append(varsAry, k)
   192  	}
   193  	sort.Strings(varsAry)
   194  
   195  	return varsAry
   196  }