github.com/sleungcy/cli@v7.1.0+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 uint64
    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  // MarshalJSON converts an application into a Cloud Controller Application.
    89  func (application Application) MarshalJSON() ([]byte, error) {
    90  	ccApp := struct {
    91  		Buildpack               *string                             `json:"buildpack,omitempty"`
    92  		Command                 *string                             `json:"command,omitempty"`
    93  		DiskQuota               *uint64                             `json:"disk_quota,omitempty"`
    94  		DockerCredentials       *DockerCredentials                  `json:"docker_credentials,omitempty"`
    95  		DockerImage             string                              `json:"docker_image,omitempty"`
    96  		EnvironmentVariables    map[string]string                   `json:"environment_json,omitempty"`
    97  		HealthCheckHTTPEndpoint *string                             `json:"health_check_http_endpoint,omitempty"`
    98  		HealthCheckTimeout      uint64                              `json:"health_check_timeout,omitempty"`
    99  		HealthCheckType         constant.ApplicationHealthCheckType `json:"health_check_type,omitempty"`
   100  		Instances               *int                                `json:"instances,omitempty"`
   101  		Memory                  *uint64                             `json:"memory,omitempty"`
   102  		Name                    string                              `json:"name,omitempty"`
   103  		SpaceGUID               string                              `json:"space_guid,omitempty"`
   104  		StackGUID               string                              `json:"stack_guid,omitempty"`
   105  		State                   constant.ApplicationState           `json:"state,omitempty"`
   106  	}{
   107  		DockerImage:          application.DockerImage,
   108  		EnvironmentVariables: application.EnvironmentVariables,
   109  		HealthCheckTimeout:   application.HealthCheckTimeout,
   110  		HealthCheckType:      application.HealthCheckType,
   111  		Name:                 application.Name,
   112  		SpaceGUID:            application.SpaceGUID,
   113  		StackGUID:            application.StackGUID,
   114  		State:                application.State,
   115  	}
   116  
   117  	if application.Buildpack.IsSet {
   118  		ccApp.Buildpack = &application.Buildpack.Value
   119  	}
   120  
   121  	if application.Command.IsSet {
   122  		ccApp.Command = &application.Command.Value
   123  	}
   124  
   125  	if application.DiskQuota.IsSet {
   126  		ccApp.DiskQuota = &application.DiskQuota.Value
   127  	}
   128  
   129  	if application.DockerCredentials.Username != "" || application.DockerCredentials.Password != "" {
   130  		ccApp.DockerCredentials = &DockerCredentials{
   131  			Username: application.DockerCredentials.Username,
   132  			Password: application.DockerCredentials.Password,
   133  		}
   134  	}
   135  
   136  	if application.Instances.IsSet {
   137  		ccApp.Instances = &application.Instances.Value
   138  	}
   139  
   140  	if application.HealthCheckType != "" {
   141  		ccApp.HealthCheckHTTPEndpoint = &application.HealthCheckHTTPEndpoint
   142  	}
   143  
   144  	if application.Memory.IsSet {
   145  		ccApp.Memory = &application.Memory.Value
   146  	}
   147  
   148  	return json.Marshal(ccApp)
   149  }
   150  
   151  // UnmarshalJSON helps unmarshal a Cloud Controller Application response.
   152  func (application *Application) UnmarshalJSON(data []byte) error {
   153  	var ccApp struct {
   154  		Metadata internal.Metadata `json:"metadata"`
   155  		Entity   struct {
   156  			Buildpack            string            `json:"buildpack"`
   157  			Command              string            `json:"command"`
   158  			DetectedBuildpack    string            `json:"detected_buildpack"`
   159  			DetectedStartCommand string            `json:"detected_start_command"`
   160  			DiskQuota            *uint64           `json:"disk_quota"`
   161  			DockerImage          string            `json:"docker_image"`
   162  			DockerCredentials    DockerCredentials `json:"docker_credentials"`
   163  			// EnvironmentVariables' values can be any type, so we must accept
   164  			// interface{}, but we convert to string.
   165  			EnvironmentVariables     map[string]interface{} `json:"environment_json"`
   166  			HealthCheckHTTPEndpoint  string                 `json:"health_check_http_endpoint"`
   167  			HealthCheckTimeout       uint64                 `json:"health_check_timeout"`
   168  			HealthCheckType          string                 `json:"health_check_type"`
   169  			Instances                json.Number            `json:"instances"`
   170  			Memory                   *uint64                `json:"memory"`
   171  			Name                     string                 `json:"name"`
   172  			PackageState             string                 `json:"package_state"`
   173  			PackageUpdatedAt         *time.Time             `json:"package_updated_at"`
   174  			SpaceGUID                string                 `json:"space_guid"`
   175  			StackGUID                string                 `json:"stack_guid"`
   176  			StagingFailedDescription string                 `json:"staging_failed_description"`
   177  			StagingFailedReason      string                 `json:"staging_failed_reason"`
   178  			State                    string                 `json:"state"`
   179  		} `json:"entity"`
   180  	}
   181  	err := cloudcontroller.DecodeJSON(data, &ccApp)
   182  	if err != nil {
   183  		return err
   184  	}
   185  
   186  	application.Buildpack.ParseValue(ccApp.Entity.Buildpack)
   187  	application.Command.ParseValue(ccApp.Entity.Command)
   188  	application.DetectedBuildpack.ParseValue(ccApp.Entity.DetectedBuildpack)
   189  	application.DetectedStartCommand.ParseValue(ccApp.Entity.DetectedStartCommand)
   190  	application.DiskQuota.ParseUint64Value(ccApp.Entity.DiskQuota)
   191  	application.DockerCredentials = ccApp.Entity.DockerCredentials
   192  	application.DockerImage = ccApp.Entity.DockerImage
   193  	application.GUID = ccApp.Metadata.GUID
   194  	application.HealthCheckHTTPEndpoint = ccApp.Entity.HealthCheckHTTPEndpoint
   195  	application.HealthCheckTimeout = ccApp.Entity.HealthCheckTimeout
   196  	application.HealthCheckType = constant.ApplicationHealthCheckType(ccApp.Entity.HealthCheckType)
   197  	application.Memory.ParseUint64Value(ccApp.Entity.Memory)
   198  	application.Name = ccApp.Entity.Name
   199  	application.PackageState = constant.ApplicationPackageState(ccApp.Entity.PackageState)
   200  	application.SpaceGUID = ccApp.Entity.SpaceGUID
   201  	application.StackGUID = ccApp.Entity.StackGUID
   202  	application.StagingFailedDescription = ccApp.Entity.StagingFailedDescription
   203  	application.StagingFailedReason = ccApp.Entity.StagingFailedReason
   204  	application.State = constant.ApplicationState(ccApp.Entity.State)
   205  
   206  	if len(ccApp.Entity.EnvironmentVariables) > 0 {
   207  		envVariableValues := map[string]string{}
   208  		for key, value := range ccApp.Entity.EnvironmentVariables {
   209  			envVariableValues[key] = fmt.Sprint(value)
   210  		}
   211  		application.EnvironmentVariables = envVariableValues
   212  	}
   213  
   214  	err = application.Instances.ParseStringValue(ccApp.Entity.Instances.String())
   215  	if err != nil {
   216  		return err
   217  	}
   218  
   219  	if ccApp.Entity.PackageUpdatedAt != nil {
   220  		application.PackageUpdatedAt = *ccApp.Entity.PackageUpdatedAt
   221  	}
   222  	return nil
   223  }
   224  
   225  // CreateApplication creates a cloud controller application in with the given
   226  // settings. SpaceGUID and Name are the only required fields.
   227  func (client *Client) CreateApplication(app Application) (Application, Warnings, error) {
   228  	body, err := json.Marshal(app)
   229  	if err != nil {
   230  		return Application{}, nil, err
   231  	}
   232  
   233  	request, err := client.newHTTPRequest(requestOptions{
   234  		RequestName: internal.PostAppRequest,
   235  		Body:        bytes.NewReader(body),
   236  	})
   237  	if err != nil {
   238  		return Application{}, nil, err
   239  	}
   240  
   241  	var updatedApp Application
   242  	response := cloudcontroller.Response{
   243  		DecodeJSONResponseInto: &updatedApp,
   244  	}
   245  
   246  	err = client.connection.Make(request, &response)
   247  	return updatedApp, response.Warnings, err
   248  }
   249  
   250  // GetApplication returns back an Application.
   251  func (client *Client) GetApplication(guid string) (Application, Warnings, error) {
   252  	request, err := client.newHTTPRequest(requestOptions{
   253  		RequestName: internal.GetAppRequest,
   254  		URIParams:   Params{"app_guid": guid},
   255  	})
   256  	if err != nil {
   257  		return Application{}, nil, err
   258  	}
   259  
   260  	var app Application
   261  	response := cloudcontroller.Response{
   262  		DecodeJSONResponseInto: &app,
   263  	}
   264  
   265  	err = client.connection.Make(request, &response)
   266  	return app, response.Warnings, err
   267  }
   268  
   269  // GetApplications returns back a list of Applications based off of the
   270  // provided filters.
   271  func (client *Client) GetApplications(filters ...Filter) ([]Application, Warnings, error) {
   272  	request, err := client.newHTTPRequest(requestOptions{
   273  		RequestName: internal.GetAppsRequest,
   274  		Query:       ConvertFilterParameters(filters),
   275  	})
   276  	if err != nil {
   277  		return nil, nil, err
   278  	}
   279  
   280  	var fullAppsList []Application
   281  	warnings, err := client.paginate(request, Application{}, func(item interface{}) error {
   282  		if app, ok := item.(Application); ok {
   283  			fullAppsList = append(fullAppsList, app)
   284  		} else {
   285  			return ccerror.UnknownObjectInListError{
   286  				Expected:   Application{},
   287  				Unexpected: item,
   288  			}
   289  		}
   290  		return nil
   291  	})
   292  
   293  	return fullAppsList, warnings, err
   294  }
   295  
   296  // GetRouteApplications returns a list of Applications based off a route
   297  // GUID and the provided filters.
   298  func (client *Client) GetRouteApplications(routeGUID string, filters ...Filter) ([]Application, Warnings, error) {
   299  	request, err := client.newHTTPRequest(requestOptions{
   300  		RequestName: internal.GetRouteAppsRequest,
   301  		URIParams:   map[string]string{"route_guid": routeGUID},
   302  		Query:       ConvertFilterParameters(filters),
   303  	})
   304  	if err != nil {
   305  		return nil, nil, err
   306  	}
   307  
   308  	var fullAppsList []Application
   309  	warnings, err := client.paginate(request, Application{}, func(item interface{}) error {
   310  		if app, ok := item.(Application); ok {
   311  			fullAppsList = append(fullAppsList, app)
   312  		} else {
   313  			return ccerror.UnknownObjectInListError{
   314  				Expected:   Application{},
   315  				Unexpected: item,
   316  			}
   317  		}
   318  		return nil
   319  	})
   320  
   321  	return fullAppsList, warnings, err
   322  }
   323  
   324  // RestageApplication restages the application with the given GUID.
   325  func (client *Client) RestageApplication(app Application) (Application, Warnings, error) {
   326  	request, err := client.newHTTPRequest(requestOptions{
   327  		RequestName: internal.PostAppRestageRequest,
   328  		URIParams:   Params{"app_guid": app.GUID},
   329  	})
   330  	if err != nil {
   331  		return Application{}, nil, err
   332  	}
   333  
   334  	var restagedApp Application
   335  	response := cloudcontroller.Response{
   336  		DecodeJSONResponseInto: &restagedApp,
   337  	}
   338  
   339  	err = client.connection.Make(request, &response)
   340  	return restagedApp, response.Warnings, err
   341  }
   342  
   343  // UpdateApplication updates the application with the given GUID. Note: Sending
   344  // DockerImage and StackGUID at the same time will result in an API error.
   345  func (client *Client) UpdateApplication(app Application) (Application, Warnings, error) {
   346  	body, err := json.Marshal(app)
   347  	if err != nil {
   348  		return Application{}, nil, err
   349  	}
   350  
   351  	request, err := client.newHTTPRequest(requestOptions{
   352  		RequestName: internal.PutAppRequest,
   353  		URIParams:   Params{"app_guid": app.GUID},
   354  		Body:        bytes.NewReader(body),
   355  	})
   356  	if err != nil {
   357  		return Application{}, nil, err
   358  	}
   359  
   360  	var updatedApp Application
   361  	response := cloudcontroller.Response{
   362  		DecodeJSONResponseInto: &updatedApp,
   363  	}
   364  
   365  	err = client.connection.Make(request, &response)
   366  	return updatedApp, response.Warnings, err
   367  }