github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+incompatible/api/cloudcontroller/ccv2/service_instance.go (about) 1 package ccv2 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "net/url" 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 ) 14 15 // ServiceInstance represents a Cloud Controller Service Instance. 16 type ServiceInstance struct { 17 // GUID is the unique service instance identifier. 18 GUID string 19 20 // Name is the name given to the service instance. 21 Name string 22 23 // SpaceGUID is the unique identifier of the space that this service instance 24 // belongs to. 25 SpaceGUID string 26 27 // ServiceGUID is the unique identifier of the service that this service 28 // instance belongs to. 29 ServiceGUID string 30 31 // ServicePlanGUID is the unique identifier of the service plan that this 32 // service instance belongs to. 33 ServicePlanGUID string 34 35 // Type is the type of service instance. 36 Type constant.ServiceInstanceType 37 38 // Tags is a list of all tags for the service instance. 39 Tags []string 40 41 // DashboardURL is the service-broker provided URL to access administrative 42 // features of the service instance. 43 DashboardURL string 44 45 // RouteServiceURL is the URL of the user-provided service to which requests 46 // for bound routes will be forwarded. 47 RouteServiceURL string 48 49 // LastOperation is the status of the last operation requested on the service 50 // instance. 51 LastOperation LastOperation 52 53 // Arbitrary parameters to pass along to the service instance. 54 Parameters map[string]interface{} 55 } 56 57 // Managed returns true if the Service Instance is a managed service. 58 func (serviceInstance ServiceInstance) Managed() bool { 59 return serviceInstance.Type == constant.ManagedService 60 } 61 62 // UnmarshalJSON helps unmarshal a Cloud Controller Service Instance response. 63 func (serviceInstance *ServiceInstance) UnmarshalJSON(data []byte) error { 64 var ccServiceInstance struct { 65 Metadata internal.Metadata 66 Entity struct { 67 Name string `json:"name"` 68 SpaceGUID string `json:"space_guid"` 69 ServiceGUID string `json:"service_guid"` 70 ServicePlanGUID string `json:"service_plan_guid"` 71 Type string `json:"type"` 72 Tags []string `json:"tags"` 73 DashboardURL string `json:"dashboard_url"` 74 RouteServiceURL string `json:"route_service_url"` 75 LastOperation LastOperation `json:"last_operation"` 76 Parameters map[string]interface{} `json:"parameters"` 77 } 78 } 79 err := cloudcontroller.DecodeJSON(data, &ccServiceInstance) 80 if err != nil { 81 return err 82 } 83 84 serviceInstance.GUID = ccServiceInstance.Metadata.GUID 85 serviceInstance.Name = ccServiceInstance.Entity.Name 86 serviceInstance.SpaceGUID = ccServiceInstance.Entity.SpaceGUID 87 serviceInstance.ServiceGUID = ccServiceInstance.Entity.ServiceGUID 88 serviceInstance.ServicePlanGUID = ccServiceInstance.Entity.ServicePlanGUID 89 serviceInstance.Type = constant.ServiceInstanceType(ccServiceInstance.Entity.Type) 90 serviceInstance.Tags = ccServiceInstance.Entity.Tags 91 serviceInstance.DashboardURL = ccServiceInstance.Entity.DashboardURL 92 serviceInstance.RouteServiceURL = ccServiceInstance.Entity.RouteServiceURL 93 serviceInstance.LastOperation = ccServiceInstance.Entity.LastOperation 94 serviceInstance.Parameters = ccServiceInstance.Entity.Parameters 95 return nil 96 } 97 98 // MarshalJSON converts an user provided service instance into a Cloud Controller user provided service instance. 99 func (serviceInstance ServiceInstance) MarshalJSON() ([]byte, error) { 100 ccObj := struct { 101 Name string `json:"name,omitempty"` 102 SpaceGUID string `json:"space_guid,omitempty"` 103 ServicePlanGUID string `json:"service_plan_guid,omitempty"` 104 Tags []string `json:"tags,omitempty"` 105 Parameters map[string]interface{} `json:"parameters,omitempty"` 106 }{ 107 Name: serviceInstance.Name, 108 SpaceGUID: serviceInstance.SpaceGUID, 109 ServicePlanGUID: serviceInstance.ServicePlanGUID, 110 Tags: serviceInstance.Tags, 111 Parameters: serviceInstance.Parameters, 112 } 113 114 return json.Marshal(ccObj) 115 } 116 117 // UserProvided returns true if the Service Instance is a user provided 118 // service. 119 func (serviceInstance ServiceInstance) UserProvided() bool { 120 return serviceInstance.Type == constant.UserProvidedService 121 } 122 123 type createServiceInstanceRequestBody struct { 124 Name string `json:"name"` 125 ServicePlanGUID string `json:"service_plan_guid"` 126 SpaceGUID string `json:"space_guid"` 127 Parameters map[string]interface{} `json:"parameters,omitempty"` 128 Tags []string `json:"tags,omitempty"` 129 } 130 131 // CreateServiceInstance posts a service instance resource with the provided 132 // attributes to the api and returns the result. 133 func (client *Client) CreateServiceInstance(spaceGUID, servicePlanGUID, serviceInstance string, parameters map[string]interface{}, tags []string) (ServiceInstance, Warnings, error) { 134 requestBody := createServiceInstanceRequestBody{ 135 Name: serviceInstance, 136 ServicePlanGUID: servicePlanGUID, 137 SpaceGUID: spaceGUID, 138 Parameters: parameters, 139 Tags: tags, 140 } 141 142 bodyBytes, err := json.Marshal(requestBody) 143 if err != nil { 144 return ServiceInstance{}, nil, err 145 } 146 147 request, err := client.newHTTPRequest(requestOptions{ 148 RequestName: internal.PostServiceInstancesRequest, 149 Body: bytes.NewReader(bodyBytes), 150 Query: url.Values{"accepts_incomplete": {"true"}}, 151 }) 152 if err != nil { 153 return ServiceInstance{}, nil, err 154 } 155 156 var instance ServiceInstance 157 response := cloudcontroller.Response{ 158 DecodeJSONResponseInto: &instance, 159 } 160 161 err = client.connection.Make(request, &response) 162 return instance, response.Warnings, err 163 } 164 165 // CreateServiceInstance posts a service instance resource with the provided 166 // attributes to the api and returns the result. 167 func (client *Client) CreateServiceInstanceFromObject(serviceInstance ServiceInstance) (ServiceInstance, Warnings, error) { 168 body, err := json.Marshal(serviceInstance) 169 if err != nil { 170 return ServiceInstance{}, nil, err 171 } 172 173 request, err := client.newHTTPRequest(requestOptions{ 174 RequestName: internal.PostServiceInstancesRequest, 175 Body: bytes.NewReader(body), 176 Query: url.Values{"accepts_incomplete": {"true"}}, 177 }) 178 if err != nil { 179 return ServiceInstance{}, nil, err 180 } 181 182 var instance ServiceInstance 183 response := cloudcontroller.Response{ 184 DecodeJSONResponseInto: &instance, 185 } 186 187 err = client.connection.Make(request, &response) 188 return instance, response.Warnings, err 189 } 190 191 // GetServiceInstance returns the service instance with the given GUID. This 192 // service can be either a managed or user provided. 193 func (client *Client) GetServiceInstance(serviceInstanceGUID string) (ServiceInstance, Warnings, error) { 194 request, err := client.newHTTPRequest(requestOptions{ 195 RequestName: internal.GetServiceInstanceRequest, 196 URIParams: Params{"service_instance_guid": serviceInstanceGUID}, 197 }) 198 if err != nil { 199 return ServiceInstance{}, nil, err 200 } 201 202 var serviceInstance ServiceInstance 203 response := cloudcontroller.Response{ 204 DecodeJSONResponseInto: &serviceInstance, 205 } 206 207 err = client.connection.Make(request, &response) 208 return serviceInstance, response.Warnings, err 209 } 210 211 // GetServiceInstances returns back a list of *managed* Service Instances based 212 // off of the provided filters. 213 func (client *Client) GetServiceInstances(filters ...Filter) ([]ServiceInstance, Warnings, error) { 214 request, err := client.newHTTPRequest(requestOptions{ 215 RequestName: internal.GetServiceInstancesRequest, 216 Query: ConvertFilterParameters(filters), 217 }) 218 if err != nil { 219 return nil, nil, err 220 } 221 222 var fullInstancesList []ServiceInstance 223 warnings, err := client.paginate(request, ServiceInstance{}, func(item interface{}) error { 224 if instance, ok := item.(ServiceInstance); ok { 225 fullInstancesList = append(fullInstancesList, instance) 226 } else { 227 return ccerror.UnknownObjectInListError{ 228 Expected: ServiceInstance{}, 229 Unexpected: item, 230 } 231 } 232 return nil 233 }) 234 235 return fullInstancesList, warnings, err 236 } 237 238 // GetSpaceServiceInstances returns back a list of Service Instances based off 239 // of the space and filters provided. User provided services will be included 240 // if includeUserProvidedServices is set to true. 241 func (client *Client) GetSpaceServiceInstances(spaceGUID string, includeUserProvidedServices bool, filters ...Filter) ([]ServiceInstance, Warnings, error) { 242 query := ConvertFilterParameters(filters) 243 244 if includeUserProvidedServices { 245 query.Add("return_user_provided_service_instances", "true") 246 } 247 248 request, err := client.newHTTPRequest(requestOptions{ 249 RequestName: internal.GetSpaceServiceInstancesRequest, 250 URIParams: map[string]string{"guid": spaceGUID}, 251 Query: query, 252 }) 253 if err != nil { 254 return nil, nil, err 255 } 256 257 var fullInstancesList []ServiceInstance 258 warnings, err := client.paginate(request, ServiceInstance{}, func(item interface{}) error { 259 if instance, ok := item.(ServiceInstance); ok { 260 fullInstancesList = append(fullInstancesList, instance) 261 } else { 262 return ccerror.UnknownObjectInListError{ 263 Expected: ServiceInstance{}, 264 Unexpected: item, 265 } 266 } 267 return nil 268 }) 269 270 return fullInstancesList, warnings, err 271 } 272 273 // UpdateServiceInstance updates the service instance with the given GUID. 274 func (client *Client) UpdateServiceInstance(serviceInstance ServiceInstance) (ServiceInstance, Warnings, error) { 275 body, err := json.Marshal(serviceInstance) 276 if err != nil { 277 return ServiceInstance{}, nil, err 278 } 279 280 request, err := client.newHTTPRequest(requestOptions{ 281 RequestName: internal.PutServiceInstanceRequest, 282 URIParams: Params{"service_instance_guid": serviceInstance.GUID}, 283 Body: bytes.NewReader(body), 284 Query: url.Values{"accepts_incomplete": {"true"}}, 285 }) 286 if err != nil { 287 return ServiceInstance{}, nil, err 288 } 289 290 var updatedObj ServiceInstance 291 response := cloudcontroller.Response{ 292 DecodeJSONResponseInto: &updatedObj, 293 } 294 295 err = client.connection.Make(request, &response) 296 return updatedObj, response.Warnings, err 297 } 298 299 // DeleteServiceInstance delete a service instance 300 func (client *Client) DeleteServiceInstance(guid string, recursive bool, purge bool) (async bool, warn Warnings, err error) { 301 request, err := client.newHTTPRequest(requestOptions{ 302 RequestName: internal.DeleteServiceInstanceRequest, 303 URIParams: Params{ 304 "service_instance_guid": guid, 305 }, 306 Query: url.Values{ 307 "accepts_incomplete": {"true"}, 308 "recursive": {fmt.Sprintf("%t", recursive)}, 309 "purge": {fmt.Sprintf("%t", purge)}, 310 }, 311 }) 312 if err != nil { 313 return false, nil, err 314 } 315 316 response := cloudcontroller.Response{} 317 318 err = client.connection.Make(request, &response) 319 return response.HTTPResponse.StatusCode == 202, response.Warnings, err 320 }