[ONOS-5756] RESTCONF protocol support for RESTCONF App
* Created a config flag in RESTCONF protocol, to allow the protocol
to be dynamically configured to work with either YMS or Dynamic Config
during runtime.
* Note that this is an interim solution to help RESTCONF migrate from
YMS to Dynamic Config. The changes will be removed once the migration
is complete.
Change-Id: I36dc8537c88965034da6238df32dde7558ac5f5c
diff --git a/protocols/restconf/server/api/src/main/java/org/onosproject/protocol/restconf/server/api/RestconfService.java b/protocols/restconf/server/api/src/main/java/org/onosproject/protocol/restconf/server/api/RestconfService.java
index 053356b..fb8a975 100644
--- a/protocols/restconf/server/api/src/main/java/org/onosproject/protocol/restconf/server/api/RestconfService.java
+++ b/protocols/restconf/server/api/src/main/java/org/onosproject/protocol/restconf/server/api/RestconfService.java
@@ -21,7 +21,11 @@
/**
* Abstraction of RESTCONF Server functionality according to the
* RESTCONF RFC (no official RFC number yet).
+ * <p>
+ * NOTE: This interface will be obsolete and will be replaced by the one
+ * in the RESTCONF application.
*/
+@Deprecated
public interface RestconfService {
/**
* Processes a GET request against a data resource. The
diff --git a/protocols/restconf/server/api/src/main/java/org/onosproject/protocol/restconf/server/api/RestconfServiceBroker.java b/protocols/restconf/server/api/src/main/java/org/onosproject/protocol/restconf/server/api/RestconfServiceBroker.java
new file mode 100644
index 0000000..b5a0c53
--- /dev/null
+++ b/protocols/restconf/server/api/src/main/java/org/onosproject/protocol/restconf/server/api/RestconfServiceBroker.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.protocol.restconf.server.api;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.glassfish.jersey.server.ChunkedOutput;
+
+/**
+ * Representation of a RESTCONF service broker. The broker
+ * provides services to the RESTCONF protocol proxy.
+ */
+public interface RestconfServiceBroker {
+ /**
+ * Processes a GET request against a data resource. The
+ * target data resource is identified by its URI. If the
+ * GET operation cannot be fulfilled due to reasons such
+ * as the nonexistence of the target resource, then a
+ * RestconfException exception is raised. The proper
+ * HTTP error status code is enclosed in the exception, so
+ * that the caller may return it to the RESTCONF client to
+ * display.
+ *
+ * @param uri URI of the target data resource
+ * @return JSON representation of the data resource
+ * @throws RestconfException if the GET operation cannot be fulfilled
+ */
+ ObjectNode runGetOperationOnDataResource(String uri)
+ throws RestconfException;
+
+ /**
+ * Processes a POST request against a data resource. The location of
+ * the target resource is passed in as a URI. And the resource's
+ * content is passed in as a JSON ObjectNode. If the POST operation
+ * cannot be fulfilled due to reasons such as wrong input URIs or
+ * syntax errors in the JSON payloads, a RestconfException exception
+ * is raised. The proper HTTP error status code is enclosed in the
+ * exception.
+ *
+ * @param uri URI of the data resource to be created
+ * @param rootNode JSON representation of the data resource
+ * @throws RestconfException if the POST operation cannot be fulfilled
+ */
+ void runPostOperationOnDataResource(String uri, ObjectNode rootNode)
+ throws RestconfException;
+
+ /**
+ * Processes a PUT request against a data resource. The location of
+ * the target resource is passed in as a URI. And the resource's
+ * content is passed in as a JSON ObjectNode. If the PUT operation
+ * cannot be fulfilled due to reasons such as wrong input URIs or
+ * syntax errors in the JSON payloads, a RestconfException exception
+ * is raised. The proper HTTP error status code is enclosed in the
+ * exception.
+ *
+ * @param uri URI of the data resource to be created or updated
+ * @param rootNode JSON representation of the data resource
+ * @throws RestconfException if the PUT operation cannot be fulfilled
+ */
+ void runPutOperationOnDataResource(String uri, ObjectNode rootNode)
+ throws RestconfException;
+
+ /**
+ * Processes the DELETE operation against a data resource. The target
+ * data resource is identified by its URI. If the DELETE operation
+ * cannot be fulfilled due reasons such as the nonexistence of the
+ * target resource, a RestconfException exception is raised. The
+ * proper HTTP error status code is enclosed in the exception.
+ *
+ * @param uri URI of the data resource to be deleted
+ * @throws RestconfException if the DELETE operation cannot be fulfilled
+ */
+ void runDeleteOperationOnDataResource(String uri) throws RestconfException;
+
+ /**
+ * Processes a PATCH operation on a data resource. The target data
+ * resource is identified by its URI passed in by the caller.
+ * And the content of the data resource is passed in as a JSON ObjectNode.
+ * If the PATCH operation cannot be fulfilled due reasons such as
+ * the nonexistence of the target resource, a RestconfException
+ * exception is raised. The proper HTTP error status code is
+ * enclosed in the exception.
+ *
+ * @param uri URI of the data resource to be patched
+ * @param rootNode JSON representation of the data resource
+ * @throws RestconfException if the PATCH operation cannot be fulfilled
+ */
+ void runPatchOperationOnDataResource(String uri, ObjectNode rootNode)
+ throws RestconfException;
+
+ /**
+ * Retrieves the RESTCONF Root directory.
+ *
+ * @return the RESTCONF Root directory
+ */
+ String getRestconfRootPath();
+
+ /**
+ * Handles an Event Stream subscription request. This function creates
+ * a worker thread to listen to events and writes to a ChunkedOutput,
+ * which is passed in from the caller. (The worker thread blocks if
+ * no events arrive.) The ChuckedOutput is a pipe to which this
+ * function acts as the writer and the caller the reader.
+ * <p>
+ * If the Event Stream cannot be subscribed due to reasons such as
+ * the nonexistence of the target stream or failure to allocate
+ * worker thread to handle the request, a RestconfException exception
+ * is raised. The proper HTTP error status code is enclosed in the
+ * exception, so that the caller may return it to the RESTCONF client
+ * to display.
+ *
+ * @param streamId ID of the RESTCONF stream to subscribe
+ * @param output A string data stream
+ * @throws RestconfException if the Event Stream cannot be subscribed
+ */
+ void subscribeEventStream(String streamId, ChunkedOutput<String> output)
+ throws RestconfException;
+}
diff --git a/protocols/restconf/server/restconfmgr/BUCK b/protocols/restconf/server/restconfmgr/BUCK
index 26d8076..8b01d0e 100644
--- a/protocols/restconf/server/restconfmgr/BUCK
+++ b/protocols/restconf/server/restconfmgr/BUCK
@@ -5,6 +5,8 @@
'//lib:javax.ws.rs-api',
'//utils/rest:onlab-rest',
'//core/store/serializers:onos-core-serializers',
+ '//incubator/api:onos-incubator-api',
+ '//apps/restconf/api:onos-apps-restconf-api',
'//protocols/restconf/server/api:onos-protocols-restconf-server-api',
'//protocols/restconf/server/utils:onos-protocols-restconf-server-utils',
'//apps/yms/api:onos-apps-yms-api',
diff --git a/protocols/restconf/server/restconfmgr/pom.xml b/protocols/restconf/server/restconfmgr/pom.xml
index 750bfe0..aaed7cc 100644
--- a/protocols/restconf/server/restconfmgr/pom.xml
+++ b/protocols/restconf/server/restconfmgr/pom.xml
@@ -68,6 +68,11 @@
<artifactId>onos-app-yms-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-restconf-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfBrokerImpl.java b/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfBrokerImpl.java
new file mode 100644
index 0000000..c204413
--- /dev/null
+++ b/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfBrokerImpl.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.protocol.restconf.server.restconfmanager;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.glassfish.jersey.server.ChunkedOutput;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.config.basics.ConfigException;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.protocol.restconf.server.api.RestconfException;
+import org.onosproject.protocol.restconf.server.api.RestconfServiceBroker;
+import org.onosproject.restconf.api.RestconfService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
+import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
+import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
+
+/**
+ * Implementation of the RestconfServiceBroker interface.
+ */
+@Component(immediate = false)
+@Service
+public class RestconfBrokerImpl implements RestconfServiceBroker {
+
+ private static final String APP_NAME = "org.onosproject.protocols.restconfserver";
+ private static final String CONFIG_KEY = "restconfCfg";
+ private static final String DYN_CONFIG_MODE = "true";
+ private static final String RESTCONF_ROOT = "/onos/restconf";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry cfgService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected org.onosproject.protocol.restconf.server.api.RestconfService restconfYms;
+
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected RestconfService restconfDynConfig;
+
+ private ApplicationId appId;
+ private boolean useDynamicConfig = false;
+
+ private final NetworkConfigListener cfgLister = new InternalConfigListener();
+ private final ConfigFactory<ApplicationId, RestconfConfig> factory =
+ new ConfigFactory<ApplicationId, RestconfConfig>(APP_SUBJECT_FACTORY,
+ RestconfConfig.class,
+ CONFIG_KEY,
+ false) {
+ @Override
+ public RestconfConfig createConfig() {
+ return new RestconfConfig();
+ }
+ };
+
+ @Activate
+ protected void activate() {
+ appId = coreService.registerApplication(APP_NAME);
+ cfgService.registerConfigFactory(factory);
+ cfgService.addListener(cfgLister);
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ cfgService.removeListener(cfgLister);
+ cfgService.unregisterConfigFactory(factory);
+ log.info("Stopped");
+ }
+
+ @Override
+ public ObjectNode runGetOperationOnDataResource(String uri)
+ throws RestconfException {
+ return useDynamicConfig ?
+ restconfDynConfig.runGetOperationOnDataResource(uri) :
+ restconfYms.runGetOperationOnDataResource(uri);
+ }
+
+
+ @Override
+ public void runPostOperationOnDataResource(String uri, ObjectNode rootNode)
+ throws RestconfException {
+ if (useDynamicConfig) {
+ restconfDynConfig.runPostOperationOnDataResource(uri, rootNode);
+ } else {
+ restconfYms.runPostOperationOnDataResource(uri, rootNode);
+ }
+ }
+
+ @Override
+ public void runPutOperationOnDataResource(String uri, ObjectNode rootNode)
+ throws RestconfException {
+ if (useDynamicConfig) {
+ restconfDynConfig.runPutOperationOnDataResource(uri, rootNode);
+ } else {
+ restconfYms.runPutOperationOnDataResource(uri, rootNode);
+ }
+ }
+
+ @Override
+ public void runDeleteOperationOnDataResource(String uri)
+ throws RestconfException {
+ if (useDynamicConfig) {
+ restconfDynConfig.runDeleteOperationOnDataResource(uri);
+ } else {
+ restconfYms.runDeleteOperationOnDataResource(uri);
+ }
+ }
+
+ @Override
+ public void runPatchOperationOnDataResource(String uri, ObjectNode rootNode)
+ throws RestconfException {
+ if (useDynamicConfig) {
+ restconfDynConfig.runPatchOperationOnDataResource(uri, rootNode);
+ } else {
+ restconfYms.runPatchOperationOnDataResource(uri, rootNode);
+ }
+ }
+
+ @Override
+ public String getRestconfRootPath() {
+ return RESTCONF_ROOT;
+ }
+
+ @Override
+ public void subscribeEventStream(String streamId,
+ ChunkedOutput<String> output)
+ throws RestconfException {
+ if (useDynamicConfig) {
+ restconfDynConfig.subscribeEventStream(streamId, output);
+ } else {
+ restconfYms.subscribeEventStream(streamId, output);
+ }
+ }
+
+ private class InternalConfigListener implements NetworkConfigListener {
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+ try {
+ useDynamicConfig = cfgService.getConfig(appId, RestconfConfig.class)
+ .useDynamicConfig().equals(DYN_CONFIG_MODE);
+ } catch (ConfigException e) {
+ log.error("Configuration error {}", e);
+ }
+ }
+
+ @Override
+ public boolean isRelevant(NetworkConfigEvent event) {
+ return event.configClass().equals(RestconfConfig.class) &&
+ (event.type() == CONFIG_ADDED ||
+ event.type() == CONFIG_UPDATED);
+ }
+ }
+}
diff --git a/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfConfig.java b/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfConfig.java
new file mode 100644
index 0000000..2dd6bb0
--- /dev/null
+++ b/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfConfig.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.protocol.restconf.server.restconfmanager;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.incubator.net.config.basics.ConfigException;
+import org.onosproject.net.config.Config;
+
+/**
+ * Configuration for TE Topology parameters.
+ */
+public class RestconfConfig extends Config<ApplicationId> {
+ private static final String CONFIG_VALUE_ERROR = "Error parsing config value";
+ private static final String USE_DNY_CONFIG = "use-dyn-config";
+
+
+ /**
+ * Retrieves whether RESTCONF should use Dynamic Config service.
+ *
+ * @return string value of true or false
+ * @throws ConfigException if the parameters are not correctly configured or
+ * conversion of the parameters fails
+ */
+ public String useDynamicConfig() throws ConfigException {
+ try {
+ return object.path(USE_DNY_CONFIG).asText();
+ } catch (IllegalArgumentException e) {
+ throw new ConfigException(CONFIG_VALUE_ERROR, e);
+ }
+ }
+
+}
diff --git a/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfManager.java b/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfManager.java
index 5d398c3..e041f1c 100644
--- a/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfManager.java
+++ b/protocols/restconf/server/restconfmgr/src/main/java/org/onosproject/protocol/restconf/server/restconfmanager/RestconfManager.java
@@ -84,6 +84,9 @@
* It provides the main logic of the RESTCONF server. It interacts with
* the YMS (YANG Management System) to run operations on the YANG data
* objects (i.e., data resources).
+ *
+ * NOTE: This implementation will be obsolete and will be replaced by the
+ * RESTCONF application.
*/
/**
diff --git a/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfWebResource.java b/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfWebResource.java
index 35abdb0..0e0a686 100644
--- a/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfWebResource.java
+++ b/protocols/restconf/server/rpp/src/main/java/org/onosproject/protocol/restconf/server/rpp/RestconfWebResource.java
@@ -21,7 +21,7 @@
import org.glassfish.jersey.server.ChunkedOutput;
import org.onosproject.protocol.restconf.server.api.Patch;
import org.onosproject.protocol.restconf.server.api.RestconfException;
-import org.onosproject.protocol.restconf.server.api.RestconfService;
+import org.onosproject.protocol.restconf.server.api.RestconfServiceBroker;
import org.onosproject.rest.AbstractWebResource;
import org.slf4j.Logger;
@@ -62,7 +62,7 @@
@Context
UriInfo uriInfo;
- private final RestconfService service = get(RestconfService.class);
+ private final RestconfServiceBroker service = get(RestconfServiceBroker.class);
private final Logger log = getLogger(getClass());
/**