github.com/cloudfoundry/cli@v7.1.0+incompatible/cf/manifest/generate_manifest.go (about)

     1  package manifest
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"code.cloudfoundry.org/cli/cf/models"
     8  
     9  	"gopkg.in/yaml.v2"
    10  
    11  	"io"
    12  
    13  	. "code.cloudfoundry.org/cli/cf/i18n"
    14  )
    15  
    16  //go:generate counterfeiter . App
    17  
    18  type App interface {
    19  	BuildpackURL(string, string)
    20  	DiskQuota(string, int64)
    21  	Memory(string, int64)
    22  	Service(string, string)
    23  	StartCommand(string, string)
    24  	EnvironmentVars(string, string, string)
    25  	HealthCheckTimeout(string, int)
    26  	HealthCheckType(string, string)
    27  	HealthCheckHTTPEndpoint(string, string)
    28  	Instances(string, int)
    29  	Route(string, string, string, string, int)
    30  	GetContents() []models.Application
    31  	Stack(string, string)
    32  	Save(f io.Writer) error
    33  }
    34  
    35  type Application struct {
    36  	Name                    string                 `yaml:"name"`
    37  	Instances               int                    `yaml:"instances,omitempty"`
    38  	Memory                  string                 `yaml:"memory,omitempty"`
    39  	DiskQuota               string                 `yaml:"disk_quota,omitempty"`
    40  	Routes                  []map[string]string    `yaml:"routes,omitempty"`
    41  	NoRoute                 bool                   `yaml:"no-route,omitempty"`
    42  	Buildpack               string                 `yaml:"buildpack,omitempty"`
    43  	Command                 string                 `yaml:"command,omitempty"`
    44  	Env                     map[string]interface{} `yaml:"env,omitempty"`
    45  	Services                []string               `yaml:"services,omitempty"`
    46  	Stack                   string                 `yaml:"stack,omitempty"`
    47  	Timeout                 int                    `yaml:"timeout,omitempty"`
    48  	HealthCheckType         string                 `yaml:"health-check-type,omitempty"`
    49  	HealthCheckHTTPEndpoint string                 `yaml:"health-check-http-endpoint,omitempty"`
    50  }
    51  
    52  type Applications struct {
    53  	Applications []Application `yaml:"applications"`
    54  }
    55  
    56  type appManifest struct {
    57  	contents []models.Application
    58  }
    59  
    60  func NewGenerator() App {
    61  	return &appManifest{}
    62  }
    63  
    64  func (m *appManifest) Stack(appName string, stackName string) {
    65  	i := m.findOrCreateApplication(appName)
    66  	m.contents[i].Stack = &models.Stack{
    67  		Name: stackName,
    68  	}
    69  }
    70  
    71  func (m *appManifest) Memory(appName string, memory int64) {
    72  	i := m.findOrCreateApplication(appName)
    73  	m.contents[i].Memory = memory
    74  }
    75  
    76  func (m *appManifest) DiskQuota(appName string, diskQuota int64) {
    77  	i := m.findOrCreateApplication(appName)
    78  	m.contents[i].DiskQuota = diskQuota
    79  }
    80  
    81  func (m *appManifest) StartCommand(appName string, cmd string) {
    82  	i := m.findOrCreateApplication(appName)
    83  	m.contents[i].Command = cmd
    84  }
    85  
    86  func (m *appManifest) BuildpackURL(appName string, url string) {
    87  	i := m.findOrCreateApplication(appName)
    88  	m.contents[i].BuildpackURL = url
    89  }
    90  
    91  func (m *appManifest) HealthCheckTimeout(appName string, timeout int) {
    92  	i := m.findOrCreateApplication(appName)
    93  	m.contents[i].HealthCheckTimeout = timeout
    94  }
    95  
    96  func (m *appManifest) HealthCheckType(appName string, healthCheckType string) {
    97  	i := m.findOrCreateApplication(appName)
    98  	m.contents[i].HealthCheckType = healthCheckType
    99  }
   100  
   101  func (m *appManifest) HealthCheckHTTPEndpoint(appName string, healthCheckHTTPEndpoint string) {
   102  	i := m.findOrCreateApplication(appName)
   103  	m.contents[i].HealthCheckHTTPEndpoint = healthCheckHTTPEndpoint
   104  }
   105  
   106  func (m *appManifest) Instances(appName string, instances int) {
   107  	i := m.findOrCreateApplication(appName)
   108  	m.contents[i].InstanceCount = instances
   109  }
   110  
   111  func (m *appManifest) Service(appName string, name string) {
   112  	i := m.findOrCreateApplication(appName)
   113  	m.contents[i].Services = append(m.contents[i].Services, models.ServicePlanSummary{
   114  		GUID: "",
   115  		Name: name,
   116  	})
   117  }
   118  
   119  func (m *appManifest) Route(appName, host, domain, path string, port int) {
   120  	i := m.findOrCreateApplication(appName)
   121  	m.contents[i].Routes = append(m.contents[i].Routes, models.RouteSummary{
   122  		Host: host,
   123  		Domain: models.DomainFields{
   124  			Name: domain,
   125  		},
   126  		Path: path,
   127  		Port: port,
   128  	})
   129  
   130  }
   131  
   132  func (m *appManifest) EnvironmentVars(appName string, key, value string) {
   133  	i := m.findOrCreateApplication(appName)
   134  	m.contents[i].EnvironmentVars[key] = value
   135  }
   136  
   137  func (m *appManifest) GetContents() []models.Application {
   138  	return m.contents
   139  }
   140  
   141  func generateAppMap(app models.Application) (Application, error) {
   142  	if app.Stack == nil {
   143  		return Application{}, errors.New(T("required attribute 'stack' missing"))
   144  	}
   145  
   146  	if app.Memory == 0 {
   147  		return Application{}, errors.New(T("required attribute 'memory' missing"))
   148  	}
   149  
   150  	if app.DiskQuota == 0 {
   151  		return Application{}, errors.New(T("required attribute 'disk_quota' missing"))
   152  	}
   153  
   154  	if app.InstanceCount == 0 {
   155  		return Application{}, errors.New(T("required attribute 'instances' missing"))
   156  	}
   157  
   158  	var services []string
   159  	for _, s := range app.Services {
   160  		services = append(services, s.Name)
   161  	}
   162  
   163  	var routes []map[string]string
   164  	for _, routeSummary := range app.Routes {
   165  		routes = append(routes, buildRoute(routeSummary))
   166  	}
   167  	m := Application{
   168  		Name:                    app.Name,
   169  		Services:                services,
   170  		Buildpack:               app.BuildpackURL,
   171  		Memory:                  fmt.Sprintf("%dM", app.Memory),
   172  		Command:                 app.Command,
   173  		Env:                     app.EnvironmentVars,
   174  		Timeout:                 app.HealthCheckTimeout,
   175  		Instances:               app.InstanceCount,
   176  		DiskQuota:               fmt.Sprintf("%dM", app.DiskQuota),
   177  		Stack:                   app.Stack.Name,
   178  		Routes:                  routes,
   179  		HealthCheckType:         app.HealthCheckType,
   180  		HealthCheckHTTPEndpoint: app.HealthCheckHTTPEndpoint,
   181  	}
   182  
   183  	if len(app.Routes) == 0 {
   184  		m.NoRoute = true
   185  
   186  	}
   187  
   188  	return m, nil
   189  }
   190  
   191  func (m *appManifest) Save(f io.Writer) error {
   192  	apps := Applications{}
   193  
   194  	for _, app := range m.contents {
   195  		appMap, mapErr := generateAppMap(app)
   196  		if mapErr != nil {
   197  			return fmt.Errorf(T("Error saving manifest: {{.Error}}", map[string]interface{}{
   198  				"Error": mapErr.Error(),
   199  			}))
   200  		}
   201  		apps.Applications = append(apps.Applications, appMap)
   202  	}
   203  
   204  	contents, err := yaml.Marshal(apps)
   205  	if err != nil {
   206  		return err
   207  	}
   208  
   209  	_, err = f.Write(contents)
   210  	if err != nil {
   211  		return err
   212  	}
   213  
   214  	return nil
   215  }
   216  
   217  func buildRoute(routeSummary models.RouteSummary) map[string]string {
   218  	var route string
   219  	if routeSummary.Host != "" {
   220  		route = fmt.Sprintf("%s.", routeSummary.Host)
   221  	}
   222  
   223  	route = fmt.Sprintf("%s%s", route, routeSummary.Domain.Name)
   224  
   225  	if routeSummary.Path != "" {
   226  		route = fmt.Sprintf("%s%s", route, routeSummary.Path)
   227  	}
   228  
   229  	if routeSummary.Port != 0 {
   230  		route = fmt.Sprintf("%s:%d", route, routeSummary.Port)
   231  	}
   232  
   233  	return map[string]string{
   234  		"route": route,
   235  	}
   236  }
   237  
   238  func (m *appManifest) findOrCreateApplication(name string) int {
   239  	for i, app := range m.contents {
   240  		if app.Name == name {
   241  			return i
   242  		}
   243  	}
   244  	m.addApplication(name)
   245  	return len(m.contents) - 1
   246  }
   247  
   248  func (m *appManifest) addApplication(name string) {
   249  	m.contents = append(m.contents, models.Application{
   250  		ApplicationFields: models.ApplicationFields{
   251  			Name:            name,
   252  			EnvironmentVars: make(map[string]interface{}),
   253  		},
   254  	})
   255  }