Jian Li
Committed by Gerrit Code Review

[ONOS-2225] Implement REST API for Flow Objectives

This commit implements REST API for Flow Objective Service.
The corresponding unit test will be followed in a separated commit.

Change-Id: I94d1dc6cfc07fc9d07fcf8c303c8e395b40ed122
...@@ -43,7 +43,8 @@ public class CoreWebApplication extends AbstractWebApplication { ...@@ -43,7 +43,8 @@ public class CoreWebApplication extends AbstractWebApplication {
43 ConfigWebResource.class, 43 ConfigWebResource.class,
44 PathsWebResource.class, 44 PathsWebResource.class,
45 StatisticsWebResource.class, 45 StatisticsWebResource.class,
46 - MetricsWebResource.class 46 + MetricsWebResource.class,
47 + FlowObjectiveWebResource.class
47 ); 48 );
48 } 49 }
49 } 50 }
...\ No newline at end of file ...\ No newline at end of file
......
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.rest.resources;
17 +
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import org.onosproject.net.DeviceId;
21 +import org.onosproject.net.flowobjective.FilteringObjective;
22 +import org.onosproject.net.flowobjective.FlowObjectiveService;
23 +import org.onosproject.net.flowobjective.ForwardingObjective;
24 +import org.onosproject.net.flowobjective.NextObjective;
25 +import org.onosproject.rest.AbstractWebResource;
26 +
27 +import javax.ws.rs.Consumes;
28 +import javax.ws.rs.GET;
29 +import javax.ws.rs.POST;
30 +import javax.ws.rs.Path;
31 +import javax.ws.rs.PathParam;
32 +import javax.ws.rs.Produces;
33 +import javax.ws.rs.core.MediaType;
34 +import javax.ws.rs.core.Response;
35 +import java.io.IOException;
36 +import java.io.InputStream;
37 +import java.net.URI;
38 +import java.net.URISyntaxException;
39 +
40 +/**
41 + * Manage flow objectives.
42 + */
43 +@Path("flowobjectives")
44 +public class FlowObjectiveWebResource extends AbstractWebResource {
45 +
46 + public static final String DEVICE_INVALID =
47 + "Invalid deviceId in objective creation request";
48 + public static final String POLICY_INVALID = "Invalid policy";
49 +
50 + final FlowObjectiveService flowObjectiveService = get(FlowObjectiveService.class);
51 + final ObjectNode root = mapper().createObjectNode();
52 +
53 + /**
54 + * Creates and installs a new filtering objective for the specified device.
55 + *
56 + * @param deviceId device identifier
57 + * @param stream filtering objective JSON
58 + * @return status of the request - CREATED if the JSON is correct,
59 + * BAD_REQUEST if the JSON is invalid
60 + * @onos.rsModel FilteringObjective
61 + */
62 + @POST
63 + @Path("{deviceId}/filter")
64 + @Consumes(MediaType.APPLICATION_JSON)
65 + @Produces(MediaType.APPLICATION_JSON)
66 + public Response createFilteringObjective(@PathParam("deviceId") String deviceId,
67 + InputStream stream) {
68 + URI location = null;
69 + try {
70 + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
71 + if (validateDeviceId(deviceId, jsonTree)) {
72 + DeviceId did = DeviceId.deviceId(deviceId);
73 + FilteringObjective filteringObjective =
74 + codec(FilteringObjective.class).decode(jsonTree, this);
75 + flowObjectiveService.filter(did, filteringObjective);
76 + location = new URI(Integer.toString(filteringObjective.id()));
77 + }
78 + } catch (IOException | URISyntaxException e) {
79 + throw new IllegalArgumentException(e);
80 + }
81 +
82 + return Response
83 + .created(location)
84 + .build();
85 + }
86 +
87 + /**
88 + * Creates and installs a new forwarding objective for the specified device.
89 + *
90 + * @param deviceId device identifier
91 + * @param stream forwarding objective JSON
92 + * @return status of the request - CREATED if the JSON is correct,
93 + * BAD_REQUEST if the JSON is invalid
94 + * @onos.rsModel ForwardingObjective
95 + */
96 + @POST
97 + @Path("{deviceId}/forward")
98 + @Consumes(MediaType.APPLICATION_JSON)
99 + @Produces(MediaType.APPLICATION_JSON)
100 + public Response createForwardingObjective(@PathParam("deviceId") String deviceId,
101 + InputStream stream) {
102 + URI location = null;
103 + try {
104 + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
105 + if (validateDeviceId(deviceId, jsonTree)) {
106 + DeviceId did = DeviceId.deviceId(deviceId);
107 + ForwardingObjective forwardingObjective =
108 + codec(ForwardingObjective.class).decode(jsonTree, this);
109 + flowObjectiveService.forward(did, forwardingObjective);
110 + location = new URI(Integer.toString(forwardingObjective.id()));
111 + }
112 + } catch (IOException | URISyntaxException e) {
113 + throw new IllegalArgumentException(e);
114 + }
115 +
116 + return Response
117 + .created(location)
118 + .build();
119 + }
120 +
121 + /**
122 + * Creates and installs a new next objective for the specified device.
123 + *
124 + * @param deviceId device identifier
125 + * @param stream next objective JSON
126 + * @return status of the request - CREATED if the JSON is correct,
127 + * BAD_REQUEST if the JSON is invalid
128 + * @onos.rsModel NextObjective
129 + */
130 + @POST
131 + @Path("{deviceId}/next")
132 + @Consumes(MediaType.APPLICATION_JSON)
133 + @Produces(MediaType.APPLICATION_JSON)
134 + public Response createNextObjective(@PathParam("deviceId") String deviceId,
135 + InputStream stream) {
136 + URI location = null;
137 + try {
138 + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
139 + if (validateDeviceId(deviceId, jsonTree)) {
140 + DeviceId did = DeviceId.deviceId(deviceId);
141 + NextObjective nextObjective =
142 + codec(NextObjective.class).decode(jsonTree, this);
143 + flowObjectiveService.next(did, nextObjective);
144 + location = new URI(Integer.toString(nextObjective.id()));
145 + }
146 + } catch (IOException | URISyntaxException e) {
147 + throw new IllegalArgumentException(e);
148 + }
149 +
150 + return Response
151 + .created(location)
152 + .build();
153 + }
154 +
155 + /**
156 + * Returns the globally unique nextId.
157 + *
158 + * @return nextId
159 + * @onos.rsModel nextid
160 + */
161 + @GET
162 + @Path("next")
163 + @Produces(MediaType.APPLICATION_JSON)
164 + public Response getNextId() {
165 + root.put("nextId", flowObjectiveService.allocateNextId());
166 + return ok(root).build();
167 + }
168 +
169 + /**
170 + * Installs the filtering rules onto the specified device.
171 + *
172 + * @param stream filtering rule JSON
173 + * @return status of the request
174 + * @onos.rsModel ObjectivePolicy
175 + */
176 + @POST
177 + @Path("policy")
178 + @Consumes(MediaType.APPLICATION_JSON)
179 + @Produces(MediaType.APPLICATION_JSON)
180 + public void initPolicy(InputStream stream) {
181 +
182 + try {
183 + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
184 + JsonNode policyJson = jsonTree.get("policy");
185 +
186 + if (policyJson == null || policyJson.asText().isEmpty()) {
187 + throw new IllegalArgumentException(POLICY_INVALID);
188 + }
189 +
190 + flowObjectiveService.initPolicy(policyJson.asText());
191 + } catch (IOException e) {
192 + throw new IllegalArgumentException(e);
193 + }
194 + }
195 +
196 + /**
197 + * Validate the deviceId that is contained in json string against the
198 + * input deviceId.
199 + *
200 + * @param deviceId device identifier
201 + * @param node object node
202 + * @return validity
203 + */
204 + private boolean validateDeviceId(String deviceId, ObjectNode node) {
205 + JsonNode specifiedDeviceId = node.get("deviceId");
206 +
207 + if (specifiedDeviceId != null &&
208 + !specifiedDeviceId.asText().equals(deviceId)) {
209 + throw new IllegalArgumentException(DEVICE_INVALID);
210 + }
211 + return true;
212 + }
213 +}
This diff is collapsed. Click to expand it.
1 +{
2 + "type": "object",
3 + "title": "forwardingObjective",
4 + "required": [
5 + "flag",
6 + "priority",
7 + "timeout",
8 + "isPermanent",
9 + "deviceId",
10 + "operation",
11 + "selector",
12 + "treatment"
13 + ],
14 + "properties": {
15 + "flag": {
16 + "type": "string",
17 + "example": "SPECIFIC"
18 + },
19 + "priority": {
20 + "type": "integer",
21 + "format": "int64",
22 + "example": 400000
23 + },
24 + "timeout": {
25 + "type": "integer",
26 + "format": "int64",
27 + "example": 0
28 + },
29 + "isPermanent": {
30 + "type": "boolean",
31 + "example": true
32 + },
33 + "deviceId": {
34 + "type": "string",
35 + "example": "of:0000000000000001"
36 + },
37 + "operation": {
38 + "type": "string",
39 + "example": "ADD"
40 + },
41 + "selector": {
42 + "type": "object",
43 + "title": "selector",
44 + "required": [
45 + "criteria"
46 + ],
47 + "properties": {
48 + "criteria": {
49 + "type": "array",
50 + "xml": {
51 + "name": "criteria",
52 + "wrapped": true
53 + },
54 + "items": {
55 + "type": "object",
56 + "title": "criteria",
57 + "properties": {
58 + "type": {
59 + "type": "string",
60 + "description": "Ethernet field name",
61 + "example": "ETH_TYPE"
62 + },
63 + "ethType": {
64 + "type": "int64",
65 + "format": "int64",
66 + "example": "0x88cc",
67 + "description": "Ethernet frame type"
68 + },
69 + "mac": {
70 + "type": "string",
71 + "example": "00:00:11:00:00:01"
72 + },
73 + "port": {
74 + "type": "int64",
75 + "format": "int64",
76 + "example": 1,
77 + "description": "Match port"
78 + },
79 + "metadata": {
80 + "type": "Hex16",
81 + "format": "Hex16",
82 + "example": "0xabcdL",
83 + "description": "Metadata passed between tables"
84 + },
85 + "vlanId": {
86 + "type": "uint16",
87 + "format": "uint16",
88 + "example": "0x1000"
89 + },
90 + "priority": {
91 + "type": "int64",
92 + "format": "int64",
93 + "example": 1,
94 + "description": "VLAN priority."
95 + },
96 + "ipDscp": {
97 + "type": "byte",
98 + "format": "byte",
99 + "description": "IP DSCP (6 bits in ToS field)"
100 + },
101 + "ipEcn": {
102 + "type": "byte",
103 + "format": "byte",
104 + "description": "IP ECN (2 bits in ToS field)."
105 + },
106 + "protocol": {
107 + "type": "uint16",
108 + "format": "uint16",
109 + "example": 1,
110 + "description": "IP protocol"
111 + },
112 + "ip": {
113 + "type": "string",
114 + "example": "10.1.1.0/24",
115 + "description": "IP source address"
116 + },
117 + "tcpPort": {
118 + "type": "integer",
119 + "format": "uint16",
120 + "example": 1,
121 + "description": "TCP source address"
122 + },
123 + "udpPort": {
124 + "type": "uint16",
125 + "format": "uint16",
126 + "example": 1,
127 + "description": "UDP source address"
128 + },
129 + "sctpPort": {
130 + "type": "uint16",
131 + "format": "uint16",
132 + "example": 1,
133 + "description": "SCTP source address"
134 + },
135 + "icmpType": {
136 + "type": "uint16",
137 + "format": "uint16",
138 + "example": 1,
139 + "description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
140 + },
141 + "icmpCode": {
142 + "type": "uint16",
143 + "format": "uint16",
144 + "example": 1,
145 + "description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
146 + },
147 + "flowLabel": {
148 + "type": "Hex16",
149 + "format": "Hex16",
150 + "example": "0xffffe",
151 + "description": "IPv6 Flow Label (RFC 6437)"
152 + },
153 + "icmpv6Type": {
154 + "type": "uint16",
155 + "format": "uint16",
156 + "example": 1,
157 + "description": "Internet Control Message Protocol for IPV6 type (RFC2463)"
158 + },
159 + "icmpv6Code": {
160 + "type": "uint16",
161 + "format": "uint16",
162 + "example": 1,
163 + "description": "Internet Control Message Protocol for IPV6 code (RFC2463)"
164 + },
165 + "targetAddress": {
166 + "type": "String",
167 + "example": "10.1.1.0/24",
168 + "description": "IPv6 Neighbor discovery target address"
169 + },
170 + "label": {
171 + "type": "int32",
172 + "format": "int32",
173 + "example": 1,
174 + "description": "MPLS label"
175 + },
176 + "exthdrFlags": {
177 + "type": "int64",
178 + "format": "int64",
179 + "example": 1,
180 + "description": "IPv6 extension header pseudo-field"
181 + },
182 + "lambda": {
183 + "type": "int64",
184 + "format": "int64",
185 + "example": 1,
186 + "description": "wavelength abstraction"
187 + },
188 + "gridType": {
189 + "type": "String",
190 + "example": "DWDM",
191 + "description": "Type of wavelength grid"
192 + },
193 + "channelSpacing": {
194 + "type": "int64",
195 + "format": "int64",
196 + "example": 100,
197 + "description": "Optical channel spacing"
198 + },
199 + "spacingMultiplier": {
200 + "type": "integer",
201 + "format": "int64",
202 + "example": 4,
203 + "description": "Optical channel spacing multiplier"
204 + },
205 + "slotGranularity": {
206 + "type": "int64",
207 + "format": "int64",
208 + "example": 8
209 + },
210 + "ochSignalId": {
211 + "type": "integer",
212 + "format": "int64",
213 + "example": 1,
214 + "description": "Optical channel signal ID"
215 + },
216 + "tunnelId": {
217 + "type": "int64",
218 + "format": "int64",
219 + "example": 5,
220 + "description": "Tunnel ID"
221 + },
222 + "ochSignalType": {
223 + "type": "int64",
224 + "format": "int64",
225 + "example": 1,
226 + "description": "Optical channel signal type"
227 + },
228 + "oduSignalId": {
229 + "type": "int64",
230 + "format": "int64",
231 + "example": 1,
232 + "description": "ODU (Optical channel Data Unit) signal ID."
233 + },
234 + "tributaryPortNumber": {
235 + "type": "int64",
236 + "format": "int64",
237 + "example": 11,
238 + "description": "OPU (Optical channel Payload Unit) port number."
239 + },
240 + "tributarySlotLen": {
241 + "type": "int64",
242 + "format": "int64",
243 + "example": 80,
244 + "description": "OPU (Optical channel Payload Unit) slot length."
245 + },
246 + "tributarySlotBitmap": {
247 + "type": "array",
248 + "title": "tributarySlotBitmap",
249 + "description": "OPU (Optical channel Payload Unit) slot bitmap.",
250 + "required": [
251 + "byte",
252 + "port"
253 + ],
254 + "items": {
255 + "type": "byte",
256 + "title": "byte",
257 + "example": 1
258 + }
259 + },
260 + "oduSignalType": {
261 + "type": "int64",
262 + "format": "int64",
263 + "example": 4,
264 + "description": "ODU (Optical channel Data Unit) signal type."
265 + }
266 + }
267 + }
268 + }
269 + }
270 + },
271 + "treatment": {
272 + "type": "object",
273 + "title": "treatment",
274 + "required": [
275 + "instructions"
276 + ],
277 + "properties": {
278 + "instructions": {
279 + "type": "array",
280 + "title": "treatment",
281 + "required": [
282 + "properties",
283 + "port"
284 + ],
285 + "items": {
286 + "type": "object",
287 + "title": "instructions",
288 + "required": [
289 + "type",
290 + "port"
291 + ],
292 + "properties": {
293 + "type": {
294 + "type": "string",
295 + "example": "OUTPUT"
296 + },
297 + "port": {
298 + "type": "string",
299 + "example": "CONTROLLER"
300 + }
301 + }
302 + }
303 + }
304 + }
305 + }
306 + }
307 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "type": "object",
3 + "title": "nextId",
4 + "required": [
5 + "id"
6 + ],
7 + "properties": {
8 + "nextId": {
9 + "type": "integer",
10 + "format": "int64",
11 + "example": 3
12 + }
13 + }
14 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "type": "object",
3 + "title": "nextObjective",
4 + "required": [
5 + "type",
6 + "priority",
7 + "timeout",
8 + "isPermanent",
9 + "deviceId",
10 + "operation",
11 + "meta",
12 + "treatments"
13 + ],
14 + "properties": {
15 + "type": {
16 + "type": "string",
17 + "example": "HASHED"
18 + },
19 + "priority": {
20 + "type": "integer",
21 + "format": "int64",
22 + "example": 400000
23 + },
24 + "timeout": {
25 + "type": "integer",
26 + "format": "int64",
27 + "example": 0
28 + },
29 + "isPermanent": {
30 + "type": "boolean",
31 + "example": true
32 + },
33 + "deviceId": {
34 + "type": "string",
35 + "example": "of:0000000000000001"
36 + },
37 + "operation": {
38 + "type": "string",
39 + "example": "ADD"
40 + },
41 + "meta": {
42 + "type": "object",
43 + "title": "meta",
44 + "required": [
45 + "criteria"
46 + ],
47 + "properties": {
48 + "criteria": {
49 + "type": "array",
50 + "xml": {
51 + "name": "criteria",
52 + "wrapped": true
53 + },
54 + "items": {
55 + "type": "object",
56 + "title": "criteria",
57 + "properties": {
58 + "type": {
59 + "type": "string",
60 + "description": "Ethernet field name",
61 + "example": "ETH_TYPE"
62 + },
63 + "ethType": {
64 + "type": "int64",
65 + "format": "int64",
66 + "example": "0x88cc",
67 + "description": "Ethernet frame type"
68 + },
69 + "mac": {
70 + "type": "string",
71 + "example": "00:00:11:00:00:01"
72 + },
73 + "port": {
74 + "type": "int64",
75 + "format": "int64",
76 + "example": 1,
77 + "description": "Match port"
78 + },
79 + "metadata": {
80 + "type": "Hex16",
81 + "format": "Hex16",
82 + "example": "0xabcdL",
83 + "description": "Metadata passed between tables"
84 + },
85 + "vlanId": {
86 + "type": "uint16",
87 + "format": "uint16",
88 + "example": "0x1000"
89 + },
90 + "priority": {
91 + "type": "int64",
92 + "format": "int64",
93 + "example": 1,
94 + "description": "VLAN priority."
95 + },
96 + "ipDscp": {
97 + "type": "byte",
98 + "format": "byte",
99 + "description": "IP DSCP (6 bits in ToS field)"
100 + },
101 + "ipEcn": {
102 + "type": "byte",
103 + "format": "byte",
104 + "description": "IP ECN (2 bits in ToS field)."
105 + },
106 + "protocol": {
107 + "type": "uint16",
108 + "format": "uint16",
109 + "example": 1,
110 + "description": "IP protocol"
111 + },
112 + "ip": {
113 + "type": "string",
114 + "example": "10.1.1.0/24",
115 + "description": "IP source address"
116 + },
117 + "tcpPort": {
118 + "type": "integer",
119 + "format": "uint16",
120 + "example": 1,
121 + "description": "TCP source address"
122 + },
123 + "udpPort": {
124 + "type": "uint16",
125 + "format": "uint16",
126 + "example": 1,
127 + "description": "UDP source address"
128 + },
129 + "sctpPort": {
130 + "type": "uint16",
131 + "format": "uint16",
132 + "example": 1,
133 + "description": "SCTP source address"
134 + },
135 + "icmpType": {
136 + "type": "uint16",
137 + "format": "uint16",
138 + "example": 1,
139 + "description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
140 + },
141 + "icmpCode": {
142 + "type": "uint16",
143 + "format": "uint16",
144 + "example": 1,
145 + "description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
146 + },
147 + "flowLabel": {
148 + "type": "Hex16",
149 + "format": "Hex16",
150 + "example": "0xffffe",
151 + "description": "IPv6 Flow Label (RFC 6437)"
152 + },
153 + "icmpv6Type": {
154 + "type": "uint16",
155 + "format": "uint16",
156 + "example": 1,
157 + "description": "Internet Control Message Protocol for IPV6 type (RFC2463)"
158 + },
159 + "icmpv6Code": {
160 + "type": "uint16",
161 + "format": "uint16",
162 + "example": 1,
163 + "description": "Internet Control Message Protocol for IPV6 code (RFC2463)"
164 + },
165 + "targetAddress": {
166 + "type": "String",
167 + "example": "10.1.1.0/24",
168 + "description": "IPv6 Neighbor discovery target address"
169 + },
170 + "label": {
171 + "type": "int32",
172 + "format": "int32",
173 + "example": 1,
174 + "description": "MPLS label"
175 + },
176 + "exthdrFlags": {
177 + "type": "int64",
178 + "format": "int64",
179 + "example": 1,
180 + "description": "IPv6 extension header pseudo-field"
181 + },
182 + "lambda": {
183 + "type": "int64",
184 + "format": "int64",
185 + "example": 1,
186 + "description": "wavelength abstraction"
187 + },
188 + "gridType": {
189 + "type": "String",
190 + "example": "DWDM",
191 + "description": "Type of wavelength grid"
192 + },
193 + "channelSpacing": {
194 + "type": "int64",
195 + "format": "int64",
196 + "example": 100,
197 + "description": "Optical channel spacing"
198 + },
199 + "spacingMultiplier": {
200 + "type": "integer",
201 + "format": "int64",
202 + "example": 4,
203 + "description": "Optical channel spacing multiplier"
204 + },
205 + "slotGranularity": {
206 + "type": "int64",
207 + "format": "int64",
208 + "example": 8
209 + },
210 + "ochSignalId": {
211 + "type": "integer",
212 + "format": "int64",
213 + "example": 1,
214 + "description": "Optical channel signal ID"
215 + },
216 + "tunnelId": {
217 + "type": "int64",
218 + "format": "int64",
219 + "example": 5,
220 + "description": "Tunnel ID"
221 + },
222 + "ochSignalType": {
223 + "type": "int64",
224 + "format": "int64",
225 + "example": 1,
226 + "description": "Optical channel signal type"
227 + },
228 + "oduSignalId": {
229 + "type": "int64",
230 + "format": "int64",
231 + "example": 1,
232 + "description": "ODU (Optical channel Data Unit) signal ID."
233 + },
234 + "tributaryPortNumber": {
235 + "type": "int64",
236 + "format": "int64",
237 + "example": 11,
238 + "description": "OPU (Optical channel Payload Unit) port number."
239 + },
240 + "tributarySlotLen": {
241 + "type": "int64",
242 + "format": "int64",
243 + "example": 80,
244 + "description": "OPU (Optical channel Payload Unit) slot length."
245 + },
246 + "tributarySlotBitmap": {
247 + "type": "array",
248 + "title": "tributarySlotBitmap",
249 + "description": "OPU (Optical channel Payload Unit) slot bitmap.",
250 + "required": [
251 + "byte",
252 + "port"
253 + ],
254 + "items": {
255 + "type": "byte",
256 + "title": "byte",
257 + "example": 1
258 + }
259 + },
260 + "oduSignalType": {
261 + "type": "int64",
262 + "format": "int64",
263 + "example": 4,
264 + "description": "ODU (Optical channel Data Unit) signal type."
265 + }
266 + }
267 + }
268 + }
269 + }
270 + },
271 + "treatments": {
272 + "type": "array",
273 + "xml": {
274 + "name": "treatments",
275 + "wrapped": true
276 + },
277 + "items": {
278 + "type": "object",
279 + "title": "treatments",
280 + "properties": {
281 + "instructions": {
282 + "type": "array",
283 + "title": "instructions",
284 + "required": [
285 + "properties",
286 + "port"
287 + ],
288 + "items": {
289 + "type": "object",
290 + "title": "instructions",
291 + "required": [
292 + "type",
293 + "port"
294 + ],
295 + "properties": {
296 + "type": {
297 + "type": "string",
298 + "example": "OUTPUT"
299 + },
300 + "port": {
301 + "type": "string",
302 + "example": "CONTROLLER"
303 + }
304 + }
305 + }
306 + }
307 + }
308 + }
309 + }
310 + }
311 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "type": "object",
3 + "title": "objectivePolicy",
4 + "required": [
5 + "policy"
6 + ],
7 + "properties": {
8 + "policy": {
9 + "type": "string",
10 + "example": "policy expression"
11 + }
12 + }
13 +}
...\ No newline at end of file ...\ No newline at end of file