github.com/cloudfoundry-attic/cli-with-i18n@v6.32.1-0.20171002233121-7401370d3b85+incompatible/api/cloudcontroller/ccv2/application.go (about)

     1  package ccv2
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"time"
     8  
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/internal"
    12  	"code.cloudfoundry.org/cli/types"
    13  )
    14  
    15  // ApplicationState is the running state of an application.
    16  type ApplicationState string
    17  
    18  const (
    19  	ApplicationStarted ApplicationState = "STARTED"
    20  	ApplicationStopped ApplicationState = "STOPPED"
    21  )
    22  
    23  // ApplicationPackageState is the staging state of application bits.
    24  type ApplicationPackageState string
    25  
    26  const (
    27  	ApplicationPackageStaged  ApplicationPackageState = "STAGED"
    28  	ApplicationPackagePending ApplicationPackageState = "PENDING"
    29  	ApplicationPackageFailed  ApplicationPackageState = "FAILED"
    30  	ApplicationPackageUnknown ApplicationPackageState = "UNKNOWN"
    31  )
    32  
    33  // ApplicationHealthCheckType is the method to reach the applications health check
    34  type ApplicationHealthCheckType string
    35  
    36  const (
    37  	ApplicationHealthCheckPort    ApplicationHealthCheckType = "port"
    38  	ApplicationHealthCheckHTTP    ApplicationHealthCheckType = "http"
    39  	ApplicationHealthCheckProcess ApplicationHealthCheckType = "process"
    40  )
    41  
    42  // Application represents a Cloud Controller Application.
    43  type Application struct {
    44  	// Buildpack is the buildpack set by the user.
    45  	Buildpack types.FilteredString
    46  
    47  	// Command is the user specified start command.
    48  	Command types.FilteredString
    49  
    50  	// DetectedBuildpack is the buildpack automatically detected.
    51  	DetectedBuildpack types.FilteredString
    52  
    53  	// DetectedStartCommand is the command used to start the application.
    54  	DetectedStartCommand types.FilteredString
    55  
    56  	// DiskQuota is the disk given to each instance, in megabytes.
    57  	DiskQuota uint64
    58  
    59  	// DockerCredentials is the authentication information for the provided
    60  	// DockerImage.
    61  	DockerCredentials DockerCredentials
    62  
    63  	// DockerImage is the docker image location.
    64  	DockerImage string
    65  
    66  	// EnvironmentVariables are the environment variables passed to the app.
    67  	EnvironmentVariables map[string]string
    68  
    69  	// GUID is the unique application identifier.
    70  	GUID string
    71  
    72  	// HealthCheckTimeout is the number of seconds for health checking of an
    73  	// staged app when starting up.
    74  	HealthCheckTimeout int
    75  
    76  	// HealthCheckType is the type of health check that will be done to the app.
    77  	HealthCheckType ApplicationHealthCheckType
    78  
    79  	// HealthCheckHTTPEndpoint is the url of the http health check endpoint.
    80  	HealthCheckHTTPEndpoint string
    81  
    82  	// Instances is the total number of app instances.
    83  	Instances types.NullInt
    84  
    85  	// Memory is the memory given to each instance, in megabytes.
    86  	Memory uint64
    87  
    88  	// Name is the name given to the application.
    89  	Name string
    90  
    91  	// PackageState represents the staging state of the application bits.
    92  	PackageState ApplicationPackageState
    93  
    94  	// PackageUpdatedAt is the last time the app bits were updated. In RFC3339.
    95  	PackageUpdatedAt time.Time
    96  
    97  	// SpaceGUID is the GUID of the app's space.
    98  	SpaceGUID string
    99  
   100  	// StackGUID is the GUID for the Stack the application is running on.
   101  	StackGUID string
   102  
   103  	// StagingFailedDescription is the verbose description of why the package
   104  	// failed to stage.
   105  	StagingFailedDescription string
   106  
   107  	// StagingFailedReason is the reason why the package failed to stage.
   108  	StagingFailedReason string
   109  
   110  	// State is the desired state of the application.
   111  	State ApplicationState
   112  }
   113  
   114  // DockerCredentials are the authentication credentials to pull a docker image
   115  // from it's repository.
   116  type DockerCredentials struct {
   117  	// Username is the username for a user that has access to a given docker
   118  	// image.
   119  	Username string `json:"username,omitempty"`
   120  
   121  	// Password is the password for the user.
   122  	Password string `json:"password,omitempty"`
   123  }
   124  
   125  // MarshalJSON converts an application into a Cloud Controller Application.
   126  func (application Application) MarshalJSON() ([]byte, error) {
   127  	ccApp := struct {
   128  		Buildpack               *string                    `json:"buildpack,omitempty"`
   129  		Command                 *string                    `json:"command,omitempty"`
   130  		DiskQuota               uint64                     `json:"disk_quota,omitempty"`
   131  		DockerCredentials       *DockerCredentials         `json:"docker_credentials,omitempty"`
   132  		DockerImage             string                     `json:"docker_image,omitempty"`
   133  		EnvironmentVariables    map[string]string          `json:"environment_json,omitempty"`
   134  		HealthCheckHTTPEndpoint string                     `json:"health_check_http_endpoint,omitempty"`
   135  		HealthCheckTimeout      int                        `json:"health_check_timeout,omitempty"`
   136  		HealthCheckType         ApplicationHealthCheckType `json:"health_check_type,omitempty"`
   137  		Instances               *int                       `json:"instances,omitempty"`
   138  		Memory                  uint64                     `json:"memory,omitempty"`
   139  		Name                    string                     `json:"name,omitempty"`
   140  		SpaceGUID               string                     `json:"space_guid,omitempty"`
   141  		StackGUID               string                     `json:"stack_guid,omitempty"`
   142  		State                   ApplicationState           `json:"state,omitempty"`
   143  	}{
   144  		DiskQuota:               application.DiskQuota,
   145  		DockerImage:             application.DockerImage,
   146  		EnvironmentVariables:    application.EnvironmentVariables,
   147  		HealthCheckHTTPEndpoint: application.HealthCheckHTTPEndpoint,
   148  		HealthCheckTimeout:      application.HealthCheckTimeout,
   149  		HealthCheckType:         application.HealthCheckType,
   150  		Memory:                  application.Memory,
   151  		Name:                    application.Name,
   152  		SpaceGUID:               application.SpaceGUID,
   153  		StackGUID:               application.StackGUID,
   154  		State:                   application.State,
   155  	}
   156  
   157  	if application.Buildpack.IsSet {
   158  		ccApp.Buildpack = &application.Buildpack.Value
   159  	}
   160  
   161  	if application.Command.IsSet {
   162  		ccApp.Command = &application.Command.Value
   163  	}
   164  
   165  	if application.DockerCredentials.Username != "" || application.DockerCredentials.Password != "" {
   166  		ccApp.DockerCredentials = &DockerCredentials{
   167  			Username: application.DockerCredentials.Username,
   168  			Password: application.DockerCredentials.Password,
   169  		}
   170  	}
   171  
   172  	if application.Instances.IsSet {
   173  		ccApp.Instances = &application.Instances.Value
   174  	}
   175  
   176  	return json.Marshal(ccApp)
   177  }
   178  
   179  // UnmarshalJSON helps unmarshal a Cloud Controller Application response.
   180  func (application *Application) UnmarshalJSON(data []byte) error {
   181  	var ccApp struct {
   182  		Metadata internal.Metadata `json:"metadata"`
   183  		Entity   struct {
   184  			Buildpack            string            `json:"buildpack"`
   185  			Command              string            `json:"command"`
   186  			DetectedBuildpack    string            `json:"detected_buildpack"`
   187  			DetectedStartCommand string            `json:"detected_start_command"`
   188  			DiskQuota            uint64            `json:"disk_quota"`
   189  			DockerImage          string            `json:"docker_image"`
   190  			DockerCredentials    DockerCredentials `json:"docker_credentials"`
   191  			// EnvironmentVariables' values can be any type, so we must accept
   192  			// interface{}, but we convert to string.
   193  			EnvironmentVariables     map[string]interface{} `json:"environment_json"`
   194  			HealthCheckHTTPEndpoint  string                 `json:"health_check_http_endpoint"`
   195  			HealthCheckTimeout       int                    `json:"health_check_timeout"`
   196  			HealthCheckType          string                 `json:"health_check_type"`
   197  			Instances                json.Number            `json:"instances"`
   198  			Memory                   uint64                 `json:"memory"`
   199  			Name                     string                 `json:"name"`
   200  			PackageState             string                 `json:"package_state"`
   201  			PackageUpdatedAt         *time.Time             `json:"package_updated_at"`
   202  			StackGUID                string                 `json:"stack_guid"`
   203  			StagingFailedDescription string                 `json:"staging_failed_description"`
   204  			StagingFailedReason      string                 `json:"staging_failed_reason"`
   205  			State                    string                 `json:"state"`
   206  		} `json:"entity"`
   207  	}
   208  
   209  	decoder := json.NewDecoder(bytes.NewBuffer(data))
   210  	decoder.UseNumber()
   211  	err := decoder.Decode(&ccApp)
   212  	if err != nil {
   213  		return err
   214  	}
   215  
   216  	application.DiskQuota = ccApp.Entity.DiskQuota
   217  	application.DockerImage = ccApp.Entity.DockerImage
   218  	application.DockerCredentials = ccApp.Entity.DockerCredentials
   219  	application.GUID = ccApp.Metadata.GUID
   220  	application.HealthCheckHTTPEndpoint = ccApp.Entity.HealthCheckHTTPEndpoint
   221  	application.HealthCheckTimeout = ccApp.Entity.HealthCheckTimeout
   222  	application.HealthCheckType = ApplicationHealthCheckType(ccApp.Entity.HealthCheckType)
   223  	application.Memory = ccApp.Entity.Memory
   224  	application.Name = ccApp.Entity.Name
   225  	application.PackageState = ApplicationPackageState(ccApp.Entity.PackageState)
   226  	application.StackGUID = ccApp.Entity.StackGUID
   227  	application.StagingFailedDescription = ccApp.Entity.StagingFailedDescription
   228  	application.StagingFailedReason = ccApp.Entity.StagingFailedReason
   229  	application.State = ApplicationState(ccApp.Entity.State)
   230  
   231  	application.Buildpack.ParseValue(ccApp.Entity.Buildpack)
   232  	application.DetectedBuildpack.ParseValue(ccApp.Entity.DetectedBuildpack)
   233  
   234  	application.Command.ParseValue(ccApp.Entity.Command)
   235  	application.DetectedStartCommand.ParseValue(ccApp.Entity.DetectedStartCommand)
   236  
   237  	if len(ccApp.Entity.EnvironmentVariables) > 0 {
   238  		envVariableValues := map[string]string{}
   239  		for key, value := range ccApp.Entity.EnvironmentVariables {
   240  			envVariableValues[key] = fmt.Sprint(value)
   241  		}
   242  		application.EnvironmentVariables = envVariableValues
   243  	}
   244  
   245  	err = application.Instances.ParseStringValue(ccApp.Entity.Instances.String())
   246  	if err != nil {
   247  		return err
   248  	}
   249  
   250  	if ccApp.Entity.PackageUpdatedAt != nil {
   251  		application.PackageUpdatedAt = *ccApp.Entity.PackageUpdatedAt
   252  	}
   253  	return nil
   254  }
   255  
   256  // CreateApplication creates a cloud controller application in with the given
   257  // settings. SpaceGUID and Name are the only required fields.
   258  func (client *Client) CreateApplication(app Application) (Application, Warnings, error) {
   259  	body, err := json.Marshal(app)
   260  	if err != nil {
   261  		return Application{}, nil, err
   262  	}
   263  
   264  	request, err := client.newHTTPRequest(requestOptions{
   265  		RequestName: internal.PostAppRequest,
   266  		Body:        bytes.NewReader(body),
   267  	})
   268  	if err != nil {
   269  		return Application{}, nil, err
   270  	}
   271  
   272  	var updatedApp Application
   273  	response := cloudcontroller.Response{
   274  		Result: &updatedApp,
   275  	}
   276  
   277  	err = client.connection.Make(request, &response)
   278  	return updatedApp, response.Warnings, err
   279  }
   280  
   281  // GetApplication returns back an Application.
   282  func (client *Client) GetApplication(guid string) (Application, Warnings, error) {
   283  	request, err := client.newHTTPRequest(requestOptions{
   284  		RequestName: internal.GetAppRequest,
   285  		URIParams:   Params{"app_guid": guid},
   286  	})
   287  	if err != nil {
   288  		return Application{}, nil, err
   289  	}
   290  
   291  	var app Application
   292  	response := cloudcontroller.Response{
   293  		Result: &app,
   294  	}
   295  
   296  	err = client.connection.Make(request, &response)
   297  	return app, response.Warnings, err
   298  }
   299  
   300  // GetApplications returns back a list of Applications based off of the
   301  // provided queries.
   302  func (client *Client) GetApplications(queries ...Query) ([]Application, Warnings, error) {
   303  	request, err := client.newHTTPRequest(requestOptions{
   304  		RequestName: internal.GetAppsRequest,
   305  		Query:       FormatQueryParameters(queries),
   306  	})
   307  	if err != nil {
   308  		return nil, nil, err
   309  	}
   310  
   311  	var fullAppsList []Application
   312  	warnings, err := client.paginate(request, Application{}, func(item interface{}) error {
   313  		if app, ok := item.(Application); ok {
   314  			fullAppsList = append(fullAppsList, app)
   315  		} else {
   316  			return ccerror.UnknownObjectInListError{
   317  				Expected:   Application{},
   318  				Unexpected: item,
   319  			}
   320  		}
   321  		return nil
   322  	})
   323  
   324  	return fullAppsList, warnings, err
   325  }
   326  
   327  // UpdateApplication updates the application with the given GUID. Note: Sending
   328  // DockerImage and StackGUID at the same time will result in an API error.
   329  func (client *Client) UpdateApplication(app Application) (Application, Warnings, error) {
   330  	body, err := json.Marshal(app)
   331  	if err != nil {
   332  		return Application{}, nil, err
   333  	}
   334  
   335  	request, err := client.newHTTPRequest(requestOptions{
   336  		RequestName: internal.PutAppRequest,
   337  		URIParams:   Params{"app_guid": app.GUID},
   338  		Body:        bytes.NewReader(body),
   339  	})
   340  	if err != nil {
   341  		return Application{}, nil, err
   342  	}
   343  
   344  	var updatedApp Application
   345  	response := cloudcontroller.Response{
   346  		Result: &updatedApp,
   347  	}
   348  
   349  	err = client.connection.Make(request, &response)
   350  	return updatedApp, response.Warnings, err
   351  }
   352  
   353  // RestageApplication restages the application with the given GUID.
   354  func (client *Client) RestageApplication(app Application) (Application, Warnings, error) {
   355  	request, err := client.newHTTPRequest(requestOptions{
   356  		RequestName: internal.PostAppRestageRequest,
   357  		URIParams:   Params{"app_guid": app.GUID},
   358  	})
   359  	if err != nil {
   360  		return Application{}, nil, err
   361  	}
   362  
   363  	var restagedApp Application
   364  	response := cloudcontroller.Response{
   365  		Result: &restagedApp,
   366  	}
   367  
   368  	err = client.connection.Make(request, &response)
   369  	return restagedApp, response.Warnings, err
   370  }
   371  
   372  // GetRouteApplications returns a list of Applications associated with a route
   373  // GUID, filtered by provided queries.
   374  func (client *Client) GetRouteApplications(routeGUID string, queryParams ...Query) ([]Application, Warnings, error) {
   375  	request, err := client.newHTTPRequest(requestOptions{
   376  		RequestName: internal.GetRouteAppsRequest,
   377  		URIParams:   map[string]string{"route_guid": routeGUID},
   378  		Query:       FormatQueryParameters(queryParams),
   379  	})
   380  	if err != nil {
   381  		return nil, nil, err
   382  	}
   383  
   384  	var fullAppsList []Application
   385  	warnings, err := client.paginate(request, Application{}, func(item interface{}) error {
   386  		if app, ok := item.(Application); ok {
   387  			fullAppsList = append(fullAppsList, app)
   388  		} else {
   389  			return ccerror.UnknownObjectInListError{
   390  				Expected:   Application{},
   391  				Unexpected: item,
   392  			}
   393  		}
   394  		return nil
   395  	})
   396  
   397  	return fullAppsList, warnings, err
   398  }