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