1package cfclient 2 3import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net/http" 10 "net/url" 11 12 "github.com/pkg/errors" 13) 14 15type ServiceInstancesResponse struct { 16 Count int `json:"total_results"` 17 Pages int `json:"total_pages"` 18 NextUrl string `json:"next_url"` 19 Resources []ServiceInstanceResource `json:"resources"` 20} 21 22type ServiceInstanceRequest struct { 23 Name string `json:"name"` 24 SpaceGuid string `json:"space_guid"` 25 ServicePlanGuid string `json:"service_plan_guid"` 26 Parameters map[string]interface{} `json:"parameters,omitempty"` 27 Tags []string `json:"tags,omitempty"` 28} 29 30type ServiceInstanceResource struct { 31 Meta Meta `json:"metadata"` 32 Entity ServiceInstance `json:"entity"` 33} 34 35type ServiceInstance struct { 36 Name string `json:"name"` 37 CreatedAt string `json:"created_at"` 38 UpdatedAt string `json:"updated_at"` 39 Credentials map[string]interface{} `json:"credentials"` 40 ServicePlanGuid string `json:"service_plan_guid"` 41 SpaceGuid string `json:"space_guid"` 42 DashboardUrl string `json:"dashboard_url"` 43 Type string `json:"type"` 44 LastOperation LastOperation `json:"last_operation"` 45 Tags []string `json:"tags"` 46 ServiceGuid string `json:"service_guid"` 47 SpaceUrl string `json:"space_url"` 48 ServicePlanUrl string `json:"service_plan_url"` 49 ServiceBindingsUrl string `json:"service_bindings_url"` 50 ServiceKeysUrl string `json:"service_keys_url"` 51 RoutesUrl string `json:"routes_url"` 52 ServiceUrl string `json:"service_url"` 53 Guid string `json:"guid"` 54 c *Client 55} 56 57type LastOperation struct { 58 Type string `json:"type"` 59 State string `json:"state"` 60 Description string `json:"description"` 61 UpdatedAt string `json:"updated_at"` 62 CreatedAt string `json:"created_at"` 63} 64 65func (c *Client) ListServiceInstancesByQuery(query url.Values) ([]ServiceInstance, error) { 66 var instances []ServiceInstance 67 68 requestUrl := "/v2/service_instances?" + query.Encode() 69 for { 70 var sir ServiceInstancesResponse 71 r := c.NewRequest("GET", requestUrl) 72 resp, err := c.DoRequest(r) 73 if err != nil { 74 return nil, errors.Wrap(err, "Error requesting service instances") 75 } 76 resBody, err := ioutil.ReadAll(resp.Body) 77 if err != nil { 78 return nil, errors.Wrap(err, "Error reading service instances request:") 79 } 80 81 err = json.Unmarshal(resBody, &sir) 82 if err != nil { 83 return nil, errors.Wrap(err, "Error unmarshaling service instances") 84 } 85 for _, instance := range sir.Resources { 86 instances = append(instances, c.mergeServiceInstance(instance)) 87 } 88 89 requestUrl = sir.NextUrl 90 if requestUrl == "" { 91 break 92 } 93 } 94 return instances, nil 95} 96 97func (c *Client) ListServiceInstances() ([]ServiceInstance, error) { 98 return c.ListServiceInstancesByQuery(nil) 99} 100 101func (c *Client) GetServiceInstanceByGuid(guid string) (ServiceInstance, error) { 102 var sir ServiceInstanceResource 103 req := c.NewRequest("GET", "/v2/service_instances/"+guid) 104 res, err := c.DoRequest(req) 105 if err != nil { 106 return ServiceInstance{}, errors.Wrap(err, "Error requesting service instance") 107 } 108 109 data, err := ioutil.ReadAll(res.Body) 110 if err != nil { 111 return ServiceInstance{}, errors.Wrap(err, "Error reading service instance response") 112 } 113 err = json.Unmarshal(data, &sir) 114 if err != nil { 115 return ServiceInstance{}, errors.Wrap(err, "Error JSON parsing service instance response") 116 } 117 return c.mergeServiceInstance(sir), nil 118} 119 120func (c *Client) ServiceInstanceByGuid(guid string) (ServiceInstance, error) { 121 return c.GetServiceInstanceByGuid(guid) 122} 123 124func (c *Client) mergeServiceInstance(instance ServiceInstanceResource) ServiceInstance { 125 instance.Entity.Guid = instance.Meta.Guid 126 instance.Entity.CreatedAt = instance.Meta.CreatedAt 127 instance.Entity.UpdatedAt = instance.Meta.UpdatedAt 128 instance.Entity.c = c 129 return instance.Entity 130} 131 132func (c *Client) CreateServiceInstance(req ServiceInstanceRequest) (ServiceInstance, error) { 133 var sir ServiceInstanceResource 134 135 buf := bytes.NewBuffer(nil) 136 err := json.NewEncoder(buf).Encode(req) 137 if err != nil { 138 return ServiceInstance{}, err 139 } 140 141 r := c.NewRequestWithBody("POST", "/v2/service_instances?accepts_incomplete=true", buf) 142 143 res, err := c.DoRequest(r) 144 if err != nil { 145 return ServiceInstance{}, err 146 } 147 148 if res.StatusCode != http.StatusAccepted && res.StatusCode != http.StatusCreated { 149 return ServiceInstance{}, errors.Wrapf(err, "Error creating service, response code: %d", res.StatusCode) 150 } 151 152 data, err := ioutil.ReadAll(res.Body) 153 if err != nil { 154 return ServiceInstance{}, errors.Wrap(err, "Error reading service instance response") 155 } 156 157 err = json.Unmarshal(data, &sir) 158 if err != nil { 159 return ServiceInstance{}, errors.Wrap(err, "Error JSON parsing service instance response") 160 } 161 162 return c.mergeServiceInstance(sir), nil 163} 164 165func (c *Client) UpdateServiceInstance(serviceInstanceGuid string, updatedConfiguration io.Reader, async bool) error { 166 u := fmt.Sprintf("/v2/service_instances/%s?accepts_incomplete=%t", serviceInstanceGuid, async) 167 resp, err := c.DoRequest(c.NewRequestWithBody("PUT", u, updatedConfiguration)) 168 if err != nil { 169 return err 170 } 171 if resp.StatusCode != http.StatusAccepted { 172 return errors.Wrapf(err, "Error updating service instance %s, response code %d", serviceInstanceGuid, resp.StatusCode) 173 } 174 return nil 175} 176 177func (c *Client) DeleteServiceInstance(guid string, recursive, async bool) error { 178 resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/service_instances/%s?recursive=%t&accepts_incomplete=%t&async=%t", guid, recursive, async, async))) 179 if err != nil { 180 return err 181 } 182 if resp.StatusCode != http.StatusAccepted { 183 return errors.Wrapf(err, "Error deleting service instance %s, response code %d", guid, resp.StatusCode) 184 } 185 return nil 186} 187