Skip to content
This repository was archived by the owner on Jun 2, 2021. It is now read-only.

Commit f961fab

Browse files
committed
V3 client can update user-provided service instance
[#171669151](https://www.pivotaltracker.com/story/show/171669151)
1 parent 408a67b commit f961fab

11 files changed

Lines changed: 587 additions & 112 deletions
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
require 'actions/mixins/service_instance_create'
2+
3+
module VCAP::CloudController
4+
class ServiceInstanceUpdateUserProvided
5+
include ServiceInstanceCreateMixin
6+
7+
class InvalidUserProvidedServiceInstance < ::StandardError
8+
end
9+
10+
def initialize(service_event_repository)
11+
@service_event_repository = service_event_repository
12+
end
13+
14+
def update(service_instance, message)
15+
logger = Steno.logger('cc.action.user_provided_service_instance_update')
16+
17+
updates = {}
18+
updates[:name] = message.name if message.requested?(:name)
19+
updates[:credentials] = message.credentials if message.requested?(:credentials)
20+
updates[:syslog_drain_url] = message.syslog_drain_url if message.requested?(:syslog_drain_url)
21+
updates[:route_service_url] = message.route_service_url if message.requested?(:route_service_url)
22+
updates[:tags] = message.tags if message.requested?(:tags)
23+
24+
service_instance.db.transaction do
25+
service_instance.update(updates)
26+
MetadataUpdate.update(service_instance, message)
27+
service_event_repository.record_user_provided_service_instance_event(:update, service_instance, message.audit_hash)
28+
end
29+
logger.info("Finished updating user-provided service_instance #{service_instance.guid}")
30+
service_instance
31+
rescue Sequel::ValidationFailed => e
32+
validation_error!(e, name: message.name)
33+
end
34+
35+
private
36+
37+
attr_reader :service_event_repository
38+
39+
def error!(message)
40+
raise InvalidUserProvidedServiceInstance.new(message)
41+
end
42+
end
43+
end

app/controllers/v3/service_instances_controller.rb

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'messages/to_many_relationship_message'
22
require 'messages/service_instances_list_message'
3-
require 'messages/service_instance_update_message'
3+
require 'messages/service_instance_update_managed_message'
4+
require 'messages/service_instance_update_user_provided_message'
45
require 'messages/service_instance_create_message'
56
require 'messages/service_instance_create_managed_message'
67
require 'messages/service_instance_create_user_provided_message'
@@ -12,6 +13,7 @@
1213
require 'actions/service_instance_share'
1314
require 'actions/service_instance_unshare'
1415
require 'actions/service_instance_update'
16+
require 'actions/service_instance_update_user_provided'
1517
require 'actions/service_instance_create_user_provided'
1618
require 'actions/service_instance_create_managed'
1719
require 'fetchers/service_instance_list_fetcher'
@@ -88,16 +90,25 @@ def create
8890
end
8991

9092
def update
91-
message = ServiceInstanceUpdateMessage.new(hashed_params[:body])
92-
unprocessable!(message.errors.full_messages) unless message.valid?
93-
9493
service_instance = ServiceInstance.first(guid: hashed_params[:guid])
9594
resource_not_found!(:service_instance) unless service_instance && can_read_service_instance?(service_instance)
9695
unauthorized! unless can_write_space?(service_instance.space)
9796

98-
service_instance = ServiceInstanceUpdate.update(service_instance, message)
97+
case service_instance
98+
when ManagedServiceInstance
99+
message = ServiceInstanceUpdateManagedMessage.new(hashed_params[:body])
100+
unprocessable!(message.errors.full_messages) unless message.valid?
99101

100-
render status: :ok, json: Presenters::V3::ServiceInstancePresenter.new(service_instance)
102+
service_instance = ServiceInstanceUpdate.update(service_instance, message)
103+
render status: :ok, json: Presenters::V3::ServiceInstancePresenter.new(service_instance)
104+
when UserProvidedServiceInstance
105+
message = ServiceInstanceUpdateUserProvidedMessage.new(hashed_params[:body])
106+
unprocessable!(message.errors.full_messages) unless message.valid?
107+
108+
service_event_repository = VCAP::CloudController::Repositories::ServiceEventRepository::WithUserActor.new(user_audit_info)
109+
service_instance = ServiceInstanceUpdateUserProvided.new(service_event_repository).update(service_instance, message)
110+
render status: :ok, json: Presenters::V3::ServiceInstancePresenter.new(service_instance)
111+
end
101112
end
102113

103114
def share_service_instance

app/messages/service_instance_update_message.rb renamed to app/messages/service_instance_update_managed_message.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
require 'messages/metadata_base_message'
22

33
module VCAP::CloudController
4-
class ServiceInstanceUpdateMessage < MetadataBaseMessage
4+
class ServiceInstanceUpdateManagedMessage < MetadataBaseMessage
55
register_allowed_keys []
66

77
validates_with NoAdditionalKeysValidator
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
require 'messages/metadata_base_message'
2+
3+
module VCAP::CloudController
4+
class ServiceInstanceUpdateUserProvidedMessage < MetadataBaseMessage
5+
register_allowed_keys [
6+
:name,
7+
:tags,
8+
:credentials,
9+
:syslog_drain_url,
10+
:route_service_url,
11+
]
12+
13+
validates_with NoAdditionalKeysValidator
14+
15+
validates :name, string: true, allow_blank: true
16+
validates :tags, array: true, allow_blank: true
17+
validates :credentials, hash: true, allow_blank: true
18+
validates :syslog_drain_url, uri: true, allow_blank: true
19+
validates :route_service_url, uri: true, allow_blank: true
20+
21+
validate :tags_must_be_strings
22+
validate :route_service_url_must_be_https
23+
24+
def audit_hash
25+
super.tap { |h| h['credentials'] = VCAP::CloudController::Presenters::Censorship::PRIVATE_DATA_HIDDEN }
26+
end
27+
28+
private
29+
30+
def route_service_url_must_be_https
31+
if route_service_url.present? && route_service_url.is_a?(String) && !route_service_url.starts_with?('https:')
32+
errors.add(:route_service_url, 'must be https')
33+
end
34+
end
35+
36+
def tags_must_be_strings
37+
if tags.present? && tags.is_a?(Array) && tags.any? { |i| !i.is_a?(String) }
38+
errors.add(:tags, 'must be a list of strings')
39+
end
40+
end
41+
end
42+
end

docs/v3/source/includes/experimental_resources/service_instances/_create.md.erb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ Name | Type | Description |
123123
---- | ---- | ----------- |
124124
**tags** | _array of strings_ | Tags are used by apps to identify service instances. They are shown in the app VCAP_SERVICES env.
125125
**parameters** | _object_ | A JSON object that is passed to the service broker.
126-
**metadata.labels** | [_label object_](#labels) | Labels applied to the service broker.
127-
**metadata.annotations** | [_annotation object_](#annotations) | Annotations applied to the service broker.
126+
**metadata.labels** | [_label object_](#labels) | Labels applied to the service instance.
127+
**metadata.annotations** | [_annotation object_](#annotations) | Annotations applied to the service instance.
128128

129129
#### Required parameters for user-provided service instance
130130

@@ -142,8 +142,8 @@ Name | Type | Description |
142142
**credentials** | _object_ | A JSON object that is made available to apps bound to this service instance.
143143
**syslog_drain_url** | _string_ | URL to which logs for bound applications will be streamed.
144144
**route_service_url** | _string_ | URL to which requests for bound routes will be forwarded. Must use the `https` protocol.
145-
**metadata.labels** | [_label object_](#labels) | Labels applied to the service broker.
146-
**metadata.annotations** | [_annotation object_](#annotations) | Annotations applied to the service broker.
145+
**metadata.labels** | [_label object_](#labels) | Labels applied to the service instance.
146+
**metadata.annotations** | [_annotation object_](#annotations) | Annotations applied to the service instance.
147147

148148
#### Permitted roles
149149
|

docs/v3/source/includes/resources/service_instances/_update.md.erb

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
### Update a service instance
22

33
```
4-
Example Request
4+
Example Request for Managed Service Instance
55
```
66

77
```shell
@@ -14,7 +14,7 @@ curl "https://api.example.org/v3/service_instances/[guid]" \
1414
```
1515

1616
```
17-
Example Response
17+
Example Response for Managed Service Instance
1818
```
1919

2020
```http
@@ -24,16 +24,68 @@ Content-Type: application/json
2424
<%= yield_content :single_service_instance, labels: { "key" => "value" }, "annotations": {"note" => "detailed information"} %>
2525
```
2626

27+
```
28+
(Experimental) Example Request for User-Provided Service Instance
29+
```
30+
31+
```shell
32+
curl "https://api.example.org/v3/service_instances/[guid]"" \
33+
-X PATCH \
34+
-H "Authorization: bearer [token]" \
35+
-H "Content-type: application/json" \
36+
-d '{
37+
"name": "my_service_instance",
38+
"credentials": {
39+
"foo": "bar",
40+
"baz": "qux"
41+
},
42+
"tags": ["foo", "bar", "baz"],
43+
"syslog_drain_url": "https://syslog.com/drain",
44+
"route_service_url": "https://route.com/service",
45+
"metadata": {
46+
"annotations": {
47+
"foo": "bar"
48+
},
49+
"labels": {
50+
"baz": "qux"
51+
}
52+
}
53+
}'
54+
```
55+
56+
```
57+
(Experimental) Example Response for User-Provided Service Instance
58+
```
59+
60+
```http
61+
HTTP/1.1 200 OK
62+
Content-Type: application/json
63+
64+
<%= yield_content :single_user_provided_service_instance, labels: { "baz" => "qux" }, annotations: {"foo" => "bar"} %>
65+
```
66+
2767
#### Definition
2868
`PATCH /v3/service_instances/:guid`
2969

30-
#### Optional parameters
70+
#### Optional parameters for managed service instances
3171

3272
Name | Type | Description
3373
---- | ---- | -----------
3474
**metadata.labels** | [_label object_](#labels) | Labels applied to the service_instance.
3575
**metadata.annotations** | [_annotation object_](#annotations) | Annotations applied to the service_instance.
3676

77+
#### Optional parameters for user-provided service instances
78+
79+
Name | Type | Description |
80+
---- | ---- | ----------- |
81+
**name** | _string_ | **Experimental** - Name of the service instance.
82+
**tags** | _array of strings_ | **Experimental** - Tags are used by apps to identify service instances. They are shown in the app VCAP_SERVICES env.
83+
**credentials** | _object_ | **Experimental** - A JSON object that is made available to apps bound to this service instance.
84+
**syslog_drain_url** | _string_ | **Experimental** - URL to which logs for bound applications will be streamed.
85+
**route_service_url** | _string_ | **Experimental** - URL to which requests for bound routes will be forwarded. Must use the `https` protocol.
86+
**metadata.labels** | [_label object_](#labels) | **Experimental** - Labels applied to the service_instance.
87+
**metadata.annotations** | [_annotation object_](#annotations) | **Experimental** - Annotations applied to the service_instance.
88+
3789
#### Permitted roles
3890
|
3991
--- | ---

0 commit comments

Comments
 (0)