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