Implementation for Restconf api call node 81/63381/1
authorjanani b <janani.b@huawei.com>
Wed, 29 Aug 2018 06:22:41 +0000 (11:52 +0530)
committerjanani b <janani.b@huawei.com>
Wed, 29 Aug 2018 06:22:41 +0000 (11:52 +0530)
Restconf Api Call Node

Issue-ID: CCSDK-372

Change-Id: I1820e97d54e734ccf73c6f48a9afcc4b59dff549
Signed-off-by: janani b <janani.b@huawei.com>
restapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/restapicall/RestapiCallNode.java
restconf-client/provider/pom.xml
restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiCallNode.java [new file with mode: 0644]
restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiUtils.java [new file with mode: 0644]
restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfapiCallNode.java [deleted file]
restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/RestconfDiscoveryNode.java
restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java
restconf-client/provider/src/main/resources/META-INF/spring/restconf-client-context.xml
restconf-client/provider/src/main/resources/META-INF/spring/restconf-client-osgi-context.xml
restconf-client/provider/src/main/resources/org/opendaylight/blueprint/restconf-client-blueprint.xml

index 46c74ff..6a9e81b 100644 (file)
 
 package org.onap.ccsdk.sli.plugins.restapicall;
 
+import com.sun.jersey.api.client.Client;
 import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
+import com.sun.jersey.api.client.filter.HTTPDigestAuthFilter;
+import com.sun.jersey.client.urlconnection.HTTPSProperties;
+import com.sun.jersey.oauth.client.OAuthClientFilter;
+import com.sun.jersey.oauth.signature.OAuthParameters;
+import com.sun.jersey.oauth.signature.OAuthSecrets;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
+import org.onap.ccsdk.sli.core.sli.SvcLogicException;
+import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.net.SocketException;
@@ -40,34 +65,8 @@ import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Set;
 
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.ws.rs.core.EntityTag;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.UriBuilder;
-
-import org.apache.commons.lang3.StringUtils;
-import org.codehaus.jettison.json.JSONException;
-import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
-import org.onap.ccsdk.sli.core.sli.SvcLogicException;
-import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.sun.jersey.api.client.Client;
-import com.sun.jersey.api.client.ClientResponse;
-import com.sun.jersey.api.client.WebResource;
-import com.sun.jersey.api.client.config.ClientConfig;
-import com.sun.jersey.api.client.config.DefaultClientConfig;
-import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
-import com.sun.jersey.api.client.filter.HTTPDigestAuthFilter;
-import com.sun.jersey.oauth.client.OAuthClientFilter;
-import com.sun.jersey.oauth.signature.OAuthParameters;
-import com.sun.jersey.oauth.signature.OAuthSecrets;
-import com.sun.jersey.client.urlconnection.HTTPSProperties;
+import static java.lang.Boolean.valueOf;
+import static org.onap.ccsdk.sli.plugins.restapicall.AuthType.fromString;
 
 public class RestapiCallNode implements SvcLogicJavaPlugin {
 
@@ -81,7 +80,7 @@ public class RestapiCallNode implements SvcLogicJavaPlugin {
     protected static final String DEFAULT_PROPERTIES_DIR = "/opt/onap/ccsdk/data/properties";
     protected static final String PROPERTIES_DIR_KEY = "SDNC_CONFIG_DIR";
 
-    protected RetryPolicyStore getRetryPolicyStore() {
+    public RetryPolicyStore getRetryPolicyStore() {
         return retryPolicyStore;
     }
 
@@ -154,7 +153,7 @@ public class RestapiCallNode implements SvcLogicJavaPlugin {
         RetryPolicy retryPolicy = null;
         HttpResponse r = new HttpResponse();
         try {
-            Parameters p = getParameters(paramMap);
+            Parameters p = getParameters(paramMap, new Parameters());
             if (p.partner != null) {
                 retryPolicy = retryPolicyStore.getRetryPolicy(p.partner);
             }
@@ -245,49 +244,88 @@ public class RestapiCallNode implements SvcLogicJavaPlugin {
             throw new SvcLogicException(String.valueOf(r.code) + ": " + r.message);
     }
 
-    protected Parameters getParameters(Map<String, String> paramMap) throws SvcLogicException {
-        Parameters p = new Parameters();
-        p.templateFileName = parseParam(paramMap, "templateFileName", false, null);
+    /**
+     * Returns parameters from the parameter map.
+     *
+     * @param paramMap parameter map
+     * @param p        parameters instance
+     * @return parameters filed instance
+     * @throws SvcLogicException when svc logic exception occurs
+     */
+    public static Parameters getParameters(Map<String, String> paramMap,
+                                           Parameters p)
+            throws SvcLogicException {
+        p.templateFileName = parseParam(paramMap, "templateFileName",
+                                        false, null);
         p.requestBody = parseParam(paramMap, "requestBody", false, null);
         p.restapiUrl = parseParam(paramMap, "restapiUrl", true, null);
         validateUrl(p.restapiUrl);
         p.restapiUser = parseParam(paramMap, "restapiUser", false, null);
-        p.restapiPassword = parseParam(paramMap, "restapiPassword", false, null);
-        p.oAuthConsumerKey = parseParam(paramMap, "oAuthConsumerKey", false, null);
-        p.oAuthConsumerSecret = parseParam(paramMap, "oAuthConsumerSecret", false, null);
-        p.oAuthSignatureMethod = parseParam(paramMap, "oAuthSignatureMethod", false, null);
+        p.restapiPassword = parseParam(paramMap, "restapiPassword", false,
+                                       null);
+        p.oAuthConsumerKey = parseParam(paramMap, "oAuthConsumerKey",
+                                        false, null);
+        p.oAuthConsumerSecret = parseParam(paramMap, "oAuthConsumerSecret",
+                                           false, null);
+        p.oAuthSignatureMethod = parseParam(paramMap, "oAuthSignatureMethod",
+                                            false, null);
         p.oAuthVersion = parseParam(paramMap, "oAuthVersion", false, null);
         p.contentType = parseParam(paramMap, "contentType", false, null);
-        p.format = Format.fromString(parseParam(paramMap, "format", false, "json"));
-        p.authtype = AuthType.fromString(parseParam(paramMap, "authType", false, "unspecified"));
-        p.httpMethod = HttpMethod.fromString(parseParam(paramMap, "httpMethod", false, "post"));
+        p.format = Format.fromString(parseParam(paramMap, "format", false,
+                                                "json"));
+        p.authtype = fromString(parseParam(paramMap, "authType", false,
+                                           "unspecified"));
+        p.httpMethod = HttpMethod.fromString(parseParam(paramMap, "httpMethod",
+                                                        false, "post"));
         p.responsePrefix = parseParam(paramMap, "responsePrefix", false, null);
         p.listNameList = getListNameList(paramMap);
         String skipSendingStr = paramMap.get("skipSending");
         p.skipSending = "true".equalsIgnoreCase(skipSendingStr);
-        p.convertResponse = Boolean.valueOf(parseParam(paramMap, "convertResponse", false, "true"));
-        p.trustStoreFileName = parseParam(paramMap, "trustStoreFileName", false, null);
-        p.trustStorePassword = parseParam(paramMap, "trustStorePassword", false, null);
-        p.keyStoreFileName = parseParam(paramMap, "keyStoreFileName", false, null);
-        p.keyStorePassword = parseParam(paramMap, "keyStorePassword", false, null);
-        p.ssl = p.trustStoreFileName != null && p.trustStorePassword != null && p.keyStoreFileName != null &&
-                p.keyStorePassword != null;
-        p.customHttpHeaders = parseParam(paramMap, "customHttpHeaders", false, null);
+        p.convertResponse = valueOf(parseParam(paramMap, "convertResponse",
+                                               false, "true"));
+        p.trustStoreFileName = parseParam(paramMap, "trustStoreFileName",
+                                          false, null);
+        p.trustStorePassword = parseParam(paramMap, "trustStorePassword",
+                                          false, null);
+        p.keyStoreFileName = parseParam(paramMap, "keyStoreFileName",
+                                        false, null);
+        p.keyStorePassword = parseParam(paramMap, "keyStorePassword",
+                                        false, null);
+        p.ssl = p.trustStoreFileName != null && p.trustStorePassword != null
+                && p.keyStoreFileName != null && p.keyStorePassword != null;
+        p.customHttpHeaders = parseParam(paramMap, "customHttpHeaders",
+                                         false, null);
         p.partner = parseParam(paramMap, "partner", false, null);
-        p.dumpHeaders = Boolean.valueOf(parseParam(paramMap, "dumpHeaders", false, null));
-        p.returnRequestPayload = Boolean.valueOf(parseParam(paramMap, "returnRequestPayload", false, null));
+        p.dumpHeaders = valueOf(parseParam(paramMap, "dumpHeaders",
+                                           false, null));
+        p.returnRequestPayload = valueOf(parseParam(
+                paramMap, "returnRequestPayload", false, null));
         return p;
     }
 
-    private void validateUrl(String restapiUrl) throws SvcLogicException {
+    /**
+     * Validates the given URL in the parameters.
+     *
+     * @param restapiUrl rest api URL
+     * @throws SvcLogicException when URL validation fails
+     */
+    private static void validateUrl(String restapiUrl)
+            throws SvcLogicException {
         try {
             URI.create(restapiUrl);
         } catch (IllegalArgumentException e) {
-            throw new SvcLogicException("Invalid input of url " + e.getLocalizedMessage(), e);
+            throw new SvcLogicException("Invalid input of url "
+                                                + e.getLocalizedMessage(), e);
         }
     }
 
-    protected Set<String> getListNameList(Map<String, String> paramMap) {
+    /**
+     * Returns the list of list name.
+     *
+     * @param paramMap parameters map
+     * @return list of list name
+     */
+    private static Set<String> getListNameList(Map<String, String> paramMap) {
         Set<String> ll = new HashSet<>();
         for (Map.Entry<String,String> entry : paramMap.entrySet())
             if (entry.getKey().startsWith("listName"))
@@ -295,7 +333,19 @@ public class RestapiCallNode implements SvcLogicJavaPlugin {
         return ll;
     }
 
-    protected String parseParam(Map<String, String> paramMap, String name, boolean required, String def)
+    /**
+     * Parses the parameter string map of property, validates if required,
+     * assigns default value if present and returns the value.
+     *
+     * @param paramMap string param map
+     * @param name     name of the property
+     * @param required if value required
+     * @param def      default value
+     * @return value of the property
+     * @throws SvcLogicException if required parameter value is empty
+     */
+    public static String parseParam(Map<String, String> paramMap, String name,
+                                    boolean required, String def)
             throws SvcLogicException {
         String s = paramMap.get(name);
 
@@ -524,7 +574,16 @@ public class RestapiCallNode implements SvcLogicJavaPlugin {
         return client;
     }
 
-    protected HttpResponse sendHttpRequest(String request, Parameters p) throws SvcLogicException {
+    /**
+     * Receives the http response for the http request sent.
+     *
+     * @param request request msg
+     * @param p       parameters
+     * @return HTTP response
+     * @throws SvcLogicException when sending http request fails
+     */
+    public HttpResponse sendHttpRequest(String request, Parameters p)
+            throws SvcLogicException {
 
         ClientConfig config = new DefaultClientConfig();
         SSLContext ssl = null;
@@ -693,7 +752,7 @@ public class RestapiCallNode implements SvcLogicJavaPlugin {
         p.oAuthVersion = parseParam(paramMap, "oAuthVersion", false, null);
         p.oAuthConsumerSecret = parseParam(paramMap, "oAuthConsumerSecret", false, null);
         p.oAuthSignatureMethod = parseParam(paramMap, "oAuthSignatureMethod", false, null);
-        p.authtype = AuthType.fromString(parseParam(paramMap, "authType", false, "unspecified"));
+        p.authtype = fromString(parseParam(paramMap, "authType", false, "unspecified"));
         return p;
     }
 
index 4183d48..0994126 100755 (executable)
         <dependency>
             <groupId>org.opendaylight.netconf</groupId>
             <artifactId>restconf-nb-rfc8040</artifactId>
-            <version>1.7.4-SNAPSHOT</version>
+            <version>1.7.3</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-parser-impl</artifactId>
+            <version>2.0.6.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>restconf-common</artifactId>
+            <version>1.7.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>restconf-nb-bierman02</artifactId>
+            <version>1.7.3</version>
+        </dependency>
     </dependencies>
 </project>
diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiCallNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiCallNode.java
new file mode 100644 (file)
index 0000000..c5f7330
--- /dev/null
@@ -0,0 +1,362 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - CCSDK
+ * ================================================================================
+ * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.ccsdk.sli.plugins.restconfapicall;
+
+import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
+import org.onap.ccsdk.sli.core.sli.SvcLogicException;
+import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
+import org.onap.ccsdk.sli.plugins.restapicall.HttpResponse;
+import org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode;
+import org.onap.ccsdk.sli.plugins.restapicall.RetryException;
+import org.onap.ccsdk.sli.plugins.restapicall.RetryPolicy;
+import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatSerializer;
+import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatSerializerContext;
+import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerFactory;
+import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.Listener;
+import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.MdsalSerializerHelper;
+import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.SerializerHelper;
+import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.YangParameters;
+import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeSerializer;
+import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeSerializer;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.UriBuilder;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.lang.String.format;
+import static org.apache.commons.lang3.StringUtils.join;
+import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.POST;
+import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.PUT;
+import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.parseParam;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.ATTEMPTS_MSG;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.COMMA;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.COMM_FAIL;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.HEADER;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.HTTP_REQ;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.HTTP_RES;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.MAX_RETRY_ERR;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.NO_MORE_RETRY;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.REQ_ERR;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.REST_API_URL;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RES_CODE;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RES_MSG;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RES_PRE;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RETRY_COUNT;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RETRY_FAIL;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.UPDATED_URL;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.getSchemaCtxFromDir;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.getYangParameters;
+import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.parseUrl;
+import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfListenerFactory.instance;
+import static org.osgi.framework.FrameworkUtil.getBundle;
+
+/**
+ * Representation of a plugin to enable RESTCONF based CRUD operations from DG.
+ */
+public class RestconfApiCallNode implements SvcLogicJavaPlugin {
+
+    /**
+     * Logger for the restconf api call node class.
+     */
+    private static final Logger log = LoggerFactory.getLogger(
+            RestconfApiCallNode.class);
+
+    /**
+     * Creates an instance of restconf api call node.
+     */
+    public RestconfApiCallNode() {
+    }
+
+    /**
+     * Sends the restconf request using the parameters map and the memory
+     * context. And this method allows the directed graphs to interact with
+     * the restconf api call node
+     *
+     * @param paramMap parameters map
+     * @param ctx      service logic context
+     * @throws SvcLogicException when svc logic exception occurs
+     */
+    public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx)
+            throws SvcLogicException {
+        sendRequest(paramMap, ctx, 0);
+    }
+
+    /**
+     * Sends the restconf request using the parameters map and the memory
+     * context along with the retry count.
+     *
+     * @param paramMap   parameters map
+     * @param ctx        service logic context
+     * @param retryCount number of retry counts
+     * @throws SvcLogicException when svc logic exception occurs
+     */
+    public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx,
+                            Integer retryCount) throws SvcLogicException {
+        RestapiCallNode rest = new RestapiCallNode();
+        RetryPolicy retryPolicy = null;
+        HttpResponse r = new HttpResponse();
+        try {
+            YangParameters p = getYangParameters(paramMap);
+            if (p.partner != null) {
+                retryPolicy = rest.getRetryPolicyStore()
+                        .getRetryPolicy(p.partner);
+            }
+
+            String pp = p.responsePrefix != null ? p.responsePrefix + '.' : "";
+            Map<String, String> props = new HashMap<>((Map)ctx.toProperties());
+            String uri = parseUrl(p.restapiUrl, p.httpMethod);
+            InstanceIdentifierContext<?> insIdCtx = getInsIdCtx(p, uri);
+
+            String req = null;
+            if (p.httpMethod == POST || p.httpMethod == PUT) {
+                req = serializeRequest(props, p, uri, insIdCtx);
+            }
+            if (req == null && p.requestBody != null) {
+                req = p.requestBody;
+            }
+
+            r = rest.sendHttpRequest(req, p);
+            if (p.returnRequestPayload && req != null) {
+                ctx.setAttribute(pp + HTTP_REQ, req);
+            }
+
+            String response = getResponse(ctx, p, pp, r);
+            if (response != null) {
+                Map<String, String> resProp = serializeResponse(
+                        p, uri, response, insIdCtx);
+                for (Map.Entry<String, String> pro : resProp.entrySet()) {
+                    ctx.setAttribute(pro.getKey(), pro.getValue());
+                }
+            }
+        } catch (SvcLogicException e) {
+            boolean shouldRetry = false;
+            if (e.getCause().getCause() instanceof SocketException) {
+                shouldRetry = true;
+            }
+
+            log.error(REQ_ERR + e.getMessage(), e);
+            String prefix = parseParam(paramMap, RES_PRE, false, null);
+            if (retryPolicy == null || shouldRetry == false) {
+                setFailureResponseStatus(ctx, prefix, e.getMessage(), r);
+            } else {
+                if (retryCount == null) {
+                    retryCount = 0;
+                }
+                log.debug(format(ATTEMPTS_MSG, retryCount,
+                                 retryPolicy.getMaximumRetries()));
+                try {
+                    retryCount = retryCount + 1;
+                    if (retryCount < retryPolicy.getMaximumRetries() + 1) {
+                        setRetryUri(paramMap, retryPolicy);
+                        log.debug(format(RETRY_COUNT, retryCount, retryPolicy
+                                .getMaximumRetries()));
+                        sendRequest(paramMap, ctx, retryCount);
+                    } else {
+                        log.debug(MAX_RETRY_ERR);
+                        setFailureResponseStatus(ctx, prefix,
+                                                 e.getMessage(), r);
+                    }
+                } catch (Exception ex) {
+                    log.error(NO_MORE_RETRY, ex);
+                    setFailureResponseStatus(ctx, prefix, RETRY_FAIL, r);
+                }
+            }
+        }
+
+        if (r != null && r.code >= 300) {
+            throw new SvcLogicException(
+                    String.valueOf(r.code) + ": " + r.message);
+        }
+    }
+
+    /**
+     * Serializes the request message to JSON or XML from the properties.
+     *
+     * @param properties properties
+     * @param params     YANG parameters
+     * @param uri        URI
+     * @param insIdCtx   instance identifier context
+     * @return JSON or XML message to be sent
+     * @throws SvcLogicException when serializing the request fails
+     */
+     protected String serializeRequest(Map<String, String> properties,
+                                    YangParameters params, String uri,
+                                    InstanceIdentifierContext insIdCtx)
+             throws SvcLogicException {
+        PropertiesNodeSerializer propSer = new MdsalPropertiesNodeSerializer(
+                insIdCtx.getSchemaNode(), insIdCtx.getSchemaContext(), uri);
+        DataFormatSerializerContext serCtx = new DataFormatSerializerContext(
+                null, uri, null, propSer);
+        DataFormatSerializer ser = DfSerializerFactory.instance()
+                .getSerializer(serCtx, params);
+         //TODO: Handling of XML annotations
+        return ser.encode(properties, null);
+    }
+
+    /**
+     * Serializes the response message from JSON or XML to the properties.
+     *
+     * @param params   YANG parameters
+     * @param uri      URI
+     * @param response response message
+     * @param insIdCtx instance identifier context
+     * @return response message as properties
+     * @throws SvcLogicException when serializing the response fails
+     */
+    protected Map<String, String> serializeResponse(YangParameters params,
+                                                  String uri, String response,
+                                                  InstanceIdentifierContext insIdCtx)
+            throws SvcLogicException {
+        PropertiesNodeSerializer propSer = new MdsalPropertiesNodeSerializer(
+                insIdCtx.getSchemaNode(), insIdCtx.getSchemaContext(), uri);
+        SerializerHelper helper = new MdsalSerializerHelper(
+                insIdCtx.getSchemaNode(), insIdCtx.getSchemaContext(), uri);
+        Listener listener = instance().getListener(helper, params);
+        DataFormatSerializerContext serCtx = new DataFormatSerializerContext(
+                listener, uri, null, propSer);
+        DataFormatSerializer ser = DfSerializerFactory.instance()
+                .getSerializer(serCtx, params);
+        return ser.decode(response);
+    }
+
+    /**
+     * Returns instance identifier context for a uri using the schema context.
+     *
+     * @param params YANG parameters
+     * @param uri    URI
+     * @return instance identifier context
+     * @throws SvcLogicException when getting schema context fails
+     */
+    private InstanceIdentifierContext<?> getInsIdCtx(YangParameters params,
+                                                     String uri)
+            throws SvcLogicException {
+        SchemaContext context = getSchemaContext(params);
+        ControllerContext contCtx = ControllerContext.getInstance();
+        contCtx.onGlobalContextUpdated(context);
+        return contCtx.toInstanceIdentifier(uri);
+    }
+
+    /**
+     * Returns the global schema context or schema context of particular YANG
+     * files present in a directory path.
+     *
+     * @param params YANG parameters
+     * @return schema context
+     * @throws SvcLogicException when schema context fetching fails
+     */
+    private SchemaContext getSchemaContext(YangParameters params)
+            throws SvcLogicException {
+        if (params.dirPath != null) {
+            return getSchemaCtxFromDir(params.dirPath);
+        }
+        BundleContext bc = getBundle(SchemaContext.class).getBundleContext();
+        SchemaContext schemaContext = null;
+        if (bc != null) {
+            ServiceReference reference = bc.getServiceReference(
+                    SchemaContext.class);
+            if (reference != null) {
+                schemaContext = (SchemaContext) bc.getService(reference);
+            }
+        }
+        return schemaContext;
+    }
+
+    /**
+     * Returns the response message body of a http response message.
+     *
+     * @param ctx    svc logic context
+     * @param params parameters
+     * @param pre    prefix to be appended
+     * @param res    http response
+     * @return response message body
+     */
+    private String getResponse(SvcLogicContext ctx, YangParameters params,
+                               String pre, HttpResponse res) {
+        ctx.setAttribute(pre + RES_CODE, String.valueOf(res.code));
+        ctx.setAttribute(pre + RES_MSG, res.message);
+
+        if (params.dumpHeaders && res.headers != null) {
+            for (Map.Entry<String, List<String>> a : res.headers.entrySet()) {
+                ctx.setAttribute(pre + HEADER + a.getKey(),
+                                 join(a.getValue(), COMMA));
+            }
+        }
+
+        if (res.body != null && res.body.trim().length() > 0) {
+            ctx.setAttribute(pre + HTTP_RES, res.body);
+            return res.body;
+        }
+        return null;
+    }
+
+    /**
+     * Sets the failure response status in the context memory.
+     *
+     * @param ctx    service logic context
+     * @param prefix prefix to be added
+     * @param errMsg error message
+     * @param res    http response
+     */
+    private void setFailureResponseStatus(SvcLogicContext ctx, String prefix,
+                                          String errMsg, HttpResponse res) {
+        res = new HttpResponse();
+        res.code = 500;
+        res.message = errMsg;
+        ctx.setAttribute(prefix + RES_CODE, String.valueOf(res.code));
+        ctx.setAttribute(prefix + RES_MSG, res.message);
+    }
+
+    /**
+     * Sets the retry URI to the param map from the retry policies different
+     * host.
+     *
+     * @param paramMap            parameter map
+     * @param retryPolicy         retry policy
+     * @throws URISyntaxException when new URI creation fails
+     * @throws RetryException     when retry policy cannot give another host
+     */
+    private void setRetryUri(Map<String, String> paramMap,
+                             RetryPolicy retryPolicy)
+            throws URISyntaxException, RetryException {
+        URI uri = new URI(paramMap.get(REST_API_URL));
+        String hostName = uri.getHost();
+        String retryString = retryPolicy.getNextHostName(uri.toString());
+
+        URI uriTwo = new URI(retryString);
+        URI retryUri = UriBuilder.fromUri(uri).host(uriTwo.getHost()).port(
+                uriTwo.getPort()).scheme(uriTwo.getScheme()).build();
+
+        paramMap.put(REST_API_URL, retryUri.toString());
+        log.debug(UPDATED_URL + retryUri.toString());
+        log.debug(format(COMM_FAIL, hostName, retryString));
+    }
+}
diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiUtils.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiUtils.java
new file mode 100644 (file)
index 0000000..e066671
--- /dev/null
@@ -0,0 +1,213 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - CCSDK
+ * ================================================================================
+ * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.ccsdk.sli.plugins.restconfapicall;
+
+import org.onap.ccsdk.sli.core.sli.SvcLogicException;
+import org.onap.ccsdk.sli.plugins.restapicall.HttpMethod;
+import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.YangParameters;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.PUT;
+import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.getParameters;
+import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.parseParam;
+import static org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode.DEFAULT_MODE;
+import static org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource.forFile;
+import static org.opendaylight.yangtools.yang.parser.rfc7950.reactor.RFC7950Reactors.defaultReactor;
+import static org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource.create;
+
+/**
+ * Utilities for restconf api call node.
+ */
+public final class RestconfApiUtils {
+
+    static final String RES_CODE = "response-code";
+
+    static final String HTTP_REQ ="httpRequest";
+
+    static final String RES_PRE = "responsePrefix";
+
+    static final String RES_MSG = "response-message";
+
+    static final String HEADER = "header.";
+
+    static final String COMMA = ",";
+
+    static final String HTTP_RES = "httpResponse";
+
+    static final String REST_API_URL = "restapiUrl";
+
+    static final String UPDATED_URL = "URL was set to";
+
+    static final String COMM_FAIL = "Failed to communicate with host %s." +
+            "Request will be re-attempted using the host %s.";
+
+    static final String RETRY_COUNT = "This is retry attempt %d out of %d";
+
+    static final String RETRY_FAIL = "Retry attempt has failed. No further " +
+            "retry shall be attempted, calling setFailureResponseStatus";
+
+    static final String NO_MORE_RETRY = "Could not attempt retry";
+
+    static final String MAX_RETRY_ERR = "Maximum retries reached, calling " +
+            "setFailureResponseStatus";
+
+    static final String ATTEMPTS_MSG = "%d attempts were made out of %d " +
+            "maximum retries";
+
+    static final String REQ_ERR = "Error sending the request: ";
+
+    private static final String SLASH = "/";
+
+    private static final String DIR_PATH = "dirPath";
+
+    private static final String URL_SYNTAX = "The following URL cannot be " +
+            "parsed into URI : ";
+
+    private static final String RESTCONF_PATH = "/restconf/operations/";
+
+    private static final String PUT_NODE_ERR = "The following URL does not " +
+            "contain minimum two nodes for PUT operation.";
+
+    private static final String YANG = ".yang";
+
+    private static final String YANG_FILE_ERR = "Unable to parse the YANG " +
+            "file provided";
+
+    //No instantiation.
+    private RestconfApiUtils() {
+    }
+
+    /**
+     * Returns the YANG parameters after parsing it from the map.
+     *
+     * @param paramMap parameters map
+     * @return YANG parameters
+     * @throws SvcLogicException when parsing of parameters map fail
+     */
+    static YangParameters getYangParameters(Map<String, String> paramMap)
+            throws SvcLogicException {
+        YangParameters param = (YangParameters) getParameters(
+                paramMap, new YangParameters());
+        param.dirPath = parseParam(paramMap, DIR_PATH, false, null);
+        return param;
+    }
+
+    /**
+     * Parses the restconf URL and gives the YANG path from it, which can be
+     * used to get schema node. If it is a PUT operation, then a node must be
+     * reduced from the url to make it always point to the parent.
+     *
+     * @param url    restconf URL
+     * @param method HTTP operation
+     * @return YANG path pointing to parent
+     * @throws SvcLogicException when parsing the URL fails
+     */
+    static String parseUrl(String url, HttpMethod method)
+            throws SvcLogicException {
+        URI uri;
+        try {
+            uri = new URI(url);
+        } catch (URISyntaxException e) {
+            throw new SvcLogicException(URL_SYNTAX + url, e);
+        }
+
+        String path = uri.getPath();
+        if (path.contains(RESTCONF_PATH)) {
+            path = path.replaceFirst(RESTCONF_PATH, "");
+        }
+        if (method == PUT) {
+            if (!path.contains(SLASH)) {
+                throw new SvcLogicException(PUT_NODE_ERR + url);
+            }
+            path = path.substring(0, path.lastIndexOf(SLASH));
+        }
+        return path;
+    }
+
+    /**
+     * Returns the schema context of the YANG files present in a directory.
+     *
+     * @param di directory path
+     * @return YANG schema context
+     * @throws SvcLogicException when YANG file reading fails
+     */
+    static SchemaContext getSchemaCtxFromDir(String di)
+            throws SvcLogicException {
+        Path d = Paths.get(di);
+        File dir = d.toFile();
+        List<File> yangFiles = new LinkedList<>();
+        getYangFiles(dir, yangFiles);
+        final Collection<YangStatementStreamSource> sources =
+                new ArrayList<>(yangFiles.size());
+        for (File file : yangFiles) {
+            try {
+                sources.add(create(forFile(file)));
+            } catch (IOException | YangSyntaxErrorException e) {
+                throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e);
+            }
+        }
+
+        final CrossSourceStatementReactor.BuildAction reactor = defaultReactor()
+                .newBuild(DEFAULT_MODE).addSources(sources);
+        try {
+            return reactor.buildEffective();
+        } catch (ReactorException e) {
+            throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Returns all the YANG files present in a directory recursively.
+     *
+     * @param dir       path of the directory
+     * @param yangFiles list of YANG files
+     */
+    private static void getYangFiles(File dir, List<File> yangFiles) {
+        if (dir.exists()) {
+            File[] files = dir.listFiles();
+            if (files != null) {
+                for (File file : files) {
+                    if (file.isFile() && file.getName().endsWith(YANG)) {
+                        yangFiles.add(file);
+                    } else if (file.isDirectory()) {
+                        getYangFiles(file, yangFiles);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfapiCallNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfapiCallNode.java
deleted file mode 100644 (file)
index 87cb92b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP - CCSDK
- * ================================================================================
- * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.ccsdk.sli.plugins.restconfapicall;
-
-import java.util.Map;
-import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
-import org.onap.ccsdk.sli.core.sli.SvcLogicException;
-import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
-
-/**
- * Representation of a plugin to enable RESTCONF based CRUD operations from DG.
- */
-public class RestconfapiCallNode implements SvcLogicJavaPlugin {
-
-    public RestconfapiCallNode() {
-    }
-
-    /**
-     * Allows Directed Graphs  the ability to interact with RESTCONF APIs.
-     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
-     * <table border="1">
-     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead>
-     *  <tbody>
-     *      <tr><td>templateFileName</td><td>Optional</td><td>full path to YANG directory that can be used to build a request</td><td>/sdncopt/bvc/resconfapi/test</td></tr>
-     *      <tr><td>restapiUrl</td><td>Mandatory</td><td>url to send the request to</td><td>https://sdncodl:8543/restconf/operations/L3VNF-API:create-update-vnf-request</td></tr>
-     *      <tr><td>restapiUser</td><td>Optional</td><td>user name to use for http basic authentication</td><td>sdnc_ws</td></tr>
-     *      <tr><td>restapiPassword</td><td>Optional</td><td>unencrypted password to use for http basic authentication</td><td>plain_password</td></tr>
-     *      <tr><td>contentType</td><td>Optional</td><td>http content type to set in the http header</td><td>usually application/json or application/xml</td></tr>
-     *      <tr><td>format</td><td>Optional</td><td>should match request body format</td><td>json or xml</td></tr>
-     *      <tr><td>httpMethod</td><td>Optional</td><td>http method to use when sending the request</td><td>get post put delete patch</td></tr>
-     *      <tr><td>responsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td><td>tmp.resconftapi.result</td></tr>
-     *      <tr><td>skipSending</td><td>Optional</td><td></td><td>true or false</td></tr>
-     *      <tr><td>convertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr>
-     *      <tr><td>customHttpHeaders</td><td>Optional</td><td>a list additional http headers to be passed in, follow the format in the example</td><td>X-CSI-MessageId=messageId,headerFieldName=headerFieldValue</td></tr>
-     *      <tr><td>dumpHeaders</td><td>Optional</td><td>when true writes http header content to context memory</td><td>true or false</td></tr>
-     *  </tbody>
-     * </table>
-     * @param ctx Reference to context memory
-     * @throws SvcLogicException
-     * @since 11.0.2
-     * @see String#split(String, int)
-     */
-    public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException {
-        //TODO
-    }
-
-}
index 34bb2ee..0490b3a 100644 (file)
@@ -24,7 +24,7 @@ import org.glassfish.jersey.media.sse.EventSource;
 import org.glassfish.jersey.media.sse.SseFeature;
 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
-import org.onap.ccsdk.sli.plugins.restconfapicall.RestconfapiCallNode;
+import org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,7 +46,7 @@ public class RestconfDiscoveryNode implements SvcLogicDiscoveryPlugin {
 
     private ExecutorService executor = Executors.newCachedThreadPool();
     private Map<String, PersistentConnection> runnableInfo = new ConcurrentHashMap<>();
-    private RestconfapiCallNode restconfapiCallNode;
+    private RestconfApiCallNode restconfApiCallNode;
 
     private volatile Map<String, SubscriptionInfo> subscriptionInfoMap = new ConcurrentHashMap<>();
     private volatile LinkedBlockingQueue<String> eventQueue = new LinkedBlockingQueue<>();
@@ -78,7 +78,7 @@ public class RestconfDiscoveryNode implements SvcLogicDiscoveryPlugin {
             throw new SvcLogicException("Subscriber Id is null");
         }
 
-        restconfapiCallNode.sendRequest(paramMap, ctx);
+        restconfApiCallNode.sendRequest(paramMap, ctx);
 
         if (getResponseCode(paramMap.get(RESPONSE_PREFIX), ctx).equals(RESPONSE_CODE_200)) {
             // TODO: save subscription id and subscriber in MYSQL
@@ -207,8 +207,8 @@ public class RestconfDiscoveryNode implements SvcLogicDiscoveryPlugin {
      *
      * @return restconfApiCallNode
      */
-    protected RestconfapiCallNode restconfapiCallNode() {
-        return restconfapiCallNode;
+    protected RestconfApiCallNode restconfapiCallNode() {
+        return restconfApiCallNode;
     }
 
     /**
@@ -216,8 +216,8 @@ public class RestconfDiscoveryNode implements SvcLogicDiscoveryPlugin {
      *
      * @param node restconfApiCallNode
      */
-    void restconfapiCallNode(RestconfapiCallNode node) {
-        restconfapiCallNode = node;
+    void restconfapiCallNode(RestconfApiCallNode node) {
+        restconfApiCallNode = node;
     }
 
     Map<String, SubscriptionInfo> subscriptionInfoMap() {
index a3e30c4..5a898df 100644 (file)
@@ -76,8 +76,8 @@ public class MdsalSerializerHelper extends SerializerHelper<SchemaNode, SchemaCo
      * @param c schema context
      * @param u URI of the request
      */
-    protected MdsalSerializerHelper(SchemaNode n, SchemaContext c,
-                                    String u) {
+    public MdsalSerializerHelper(SchemaNode n, SchemaContext c,
+                                 String u) {
         super(n, c, u);
         Namespace ns = new Namespace(n.getQName().getLocalName(),
                                      n.getQName().getNamespace(),
index 34344fe..f99f4f8 100644 (file)
 
     <!-- context:property-placeholder location="file:${SDNC_CONFIG_DIR}/ueb.properties" /-->
 
-    <bean id="restconfapiCallNode" class="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfapiCallNode">
+    <bean id="restconfApiCallNode" class="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode">
         <property name="uebServers" value="${servers}" />
     </bean>
 
     <bean id="restconfDiscoveryNode" class="org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode">
-        <property name="restconfapiCallNode" ref="restconfapiCallNode" />
+        <property name="restconfApiCallNode" ref="restconfApiCallNode" />
     </bean>
 
 </beans>
index d56e2fc..5a9f22b 100644 (file)
@@ -26,7 +26,7 @@
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
 
-    <service ref="restconfapiCallNode" interface="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfapiCallNode" />
+    <service ref="restconfApiCallNode" interface="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode" />
     <service ref="restconfDiscoveryNode" interface="org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode" />
 
 </beans:beans>
index 149ed9f..91c31ef 100755 (executable)
            xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
            odl:use-default-for-reference-types="true">
 
-    <bean id="restconfapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfapiCallNode" />
+    <bean id="restconfapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode" />
     <bean id="restconfDiscoveryNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode" />
 
     <service ref="restconfapiCallNodeProvider">
         <interfaces>
-            <value>org.onap.ccsdk.sli.plugins.restconfapicall.RestconfapiCallNode</value>
+            <value>org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode</value>
         </interfaces>
     </service>