blob: 27c1e86867eeb63850ee73f846f38631a2d92ec0 [file] [log] [blame]
Sean Condon06613e92017-06-09 15:14:01 +01001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Sean Condon06613e92017-06-09 15:14:01 +01003 *
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 */
16package org.onosproject.drivers.microsemi.yang.impl;
17
18import java.io.ByteArrayInputStream;
19import java.io.IOException;
20import java.io.InputStream;
21import java.util.List;
22import java.util.Set;
23import java.util.regex.Pattern;
24
25import com.google.common.base.Charsets;
26import com.google.common.io.ByteSource;
27import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
30import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
32import org.apache.felix.scr.annotations.Service;
33import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.netconf.DatastoreId;
36import org.onosproject.netconf.NetconfException;
37import org.onosproject.netconf.NetconfSession;
Sean Condon0e89bda2017-03-21 14:23:19 +000038import org.onosproject.yang.gen.v1.mseacfm.rev20160229.mseacfm.mefcfm.maintenancedomain.maintenanceassociation.CcmIntervalEnum;
39import org.onosproject.yang.gen.v1.mseasoampm.rev20160229.mseasoampm.mefcfm.maintenancedomain.maintenanceassociation.maintenanceassociationendpoint.augmentedmseacfmmaintenanceassociationendpoint.lossmeasurements.lossmeasurement.MessagePeriodEnum;
Sean Condon06613e92017-06-09 15:14:01 +010040import org.onosproject.yang.model.ModelConverter;
41import org.onosproject.yang.model.ModelObjectData;
42import org.onosproject.yang.model.ResourceData;
43import org.onosproject.yang.model.ResourceId;
44import org.onosproject.yang.model.SchemaContext;
45import org.onosproject.yang.model.SchemaContextProvider;
46import org.onosproject.yang.runtime.AnnotatedNodeInfo;
47import org.onosproject.yang.runtime.CompositeData;
48import org.onosproject.yang.runtime.CompositeStream;
49import org.onosproject.yang.runtime.DefaultCompositeData;
50import org.onosproject.yang.runtime.DefaultCompositeStream;
51import org.onosproject.yang.runtime.DefaultYangSerializerContext;
52import org.onosproject.yang.runtime.YangModelRegistry;
53import org.onosproject.yang.runtime.YangSerializer;
54import org.onosproject.yang.runtime.YangSerializerContext;
55import org.onosproject.yang.runtime.YangSerializerRegistry;
56import org.onosproject.yang.serializers.xml.XmlSerializer;
57import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
60/**
61 * Abstract class that implements some of the core functions of a YANG model service.
62 *
63 */
64@Component(immediate = true)
65@Service
66public abstract class AbstractYangServiceImpl {
67 public static final String NC_OPERATION = "nc:operation";
68 public static final String OP_DELETE = "delete";
69
70 protected final Logger log = LoggerFactory.getLogger(getClass());
71 protected boolean alreadyLoaded = false;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected CoreService coreService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected YangModelRegistry yangModelRegistry;
78
79// @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80// protected SchemaContextProvider schemaContextProvider;
81
82 protected ApplicationId appId;
83
84 // xSer is not a service and is a class variable. Can be lost on deactivate.
85 // Must be recreated on activate
86 protected XmlSerializer xSer;
87 protected YangSerializerContext yCtx;
88
89 protected static final Pattern REGEX_XML_HEADER =
90 Pattern.compile("(<\\?xml).*(\\?>)", Pattern.DOTALL);
91 protected static final Pattern REGEX_RPC_REPLY =
92 Pattern.compile("(<rpc-reply)[ ]*" +
93 "(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\")[ ]*" +
94 "(message-id=\")[0-9]*(\">)", Pattern.DOTALL);
95 protected static final Pattern REGEX_RPC_REPLY_DATA_NS =
96 Pattern.compile("(<data)[ ]*(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)");
97 protected static final Pattern REGEX_RPC_REPLY_DATA =
98 Pattern.compile("(<data>)");
99 protected static final Pattern REGEX_RPC_REPLY_DATA_CLOSE =
100 Pattern.compile("(</data>)");
101 protected static final Pattern REGEX_RPC_REPLY_DATA_EMPTY =
102 Pattern.compile("(<data/>)");
103 protected static final Pattern REGEX_RPC_REPLY_CLOSE =
104 Pattern.compile("(</rpc-reply>)");
Sean Condon0e89bda2017-03-21 14:23:19 +0000105 protected static final Pattern REGEX_RPC_OK =
106 Pattern.compile("\\R?\\s*(<ok/>)\\R?");
Sean Condon06613e92017-06-09 15:14:01 +0100107 @Activate
108 public void activate() {
109 Set<YangSerializer> yangSer = ((YangSerializerRegistry) yangModelRegistry).getSerializers();
110 yangSer.forEach(ser -> {
111 if (ser instanceof XmlSerializer) {
112 xSer = (XmlSerializer) ser;
113 }
114 });
115 SchemaContext context = ((SchemaContextProvider) yangModelRegistry)
116 .getSchemaContext(ResourceId.builder().addBranchPointSchema("/", null).build());
117
118 yCtx = new DefaultYangSerializerContext(context, null);
119 };
120
121 @Deactivate
122 public void deactivate() {
123 alreadyLoaded = false;
124 }
125
126 /**
127 * Internal method to generically make a NETCONF get query from YANG objects.
128 * @param moFilter A YANG object model
129 * @param session A NETCONF session
130 * @return YangObjectModel
131 * @throws NetconfException if the session has any error
132 */
133 protected final ModelObjectData getNetconfObject(
134 ModelObjectData moFilter, NetconfSession session)
135 throws NetconfException {
136
137 return getConfigNetconfObject(moFilter, session, null);
138 }
139
140 /**
141 * Internal method to generically make a NETCONF get-config query from YANG objects.
142 *
143 * @param moFilter A YANG object model
144 * @param session A NETCONF session
145 * @param targetDs - running,candidate or startup
146 * @return YangObjectModel
147 * @throws NetconfException if the session has any error
148 */
149 protected final ModelObjectData getConfigNetconfObject(
150 ModelObjectData moFilter, NetconfSession session, DatastoreId targetDs)
151 throws NetconfException {
152 if (session == null) {
153 throw new NetconfException("Session is null when calling getConfigNetconfObject()");
154 }
155
156 if (moFilter == null) {
157 throw new NetconfException("Query object cannot be null");
158 }
159
160 String xmlQueryStr = encodeMoToXmlStr(moFilter, null);
161
162 log.debug("Sending <get-(config)> query on NETCONF session " + session.getSessionId() +
163 ":\n" + xmlQueryStr);
164 String xmlResult;
165 if (targetDs == null) {
166 xmlResult = session.get(xmlQueryStr, null);
167 } else {
168 xmlResult = session.getConfig(targetDs, xmlQueryStr);
169 }
170 xmlResult = removeRpcReplyData(xmlResult);
171
172 DefaultCompositeStream resultDcs = new DefaultCompositeStream(
173 null, new ByteArrayInputStream(xmlResult.getBytes()));
174 CompositeData compositeData = xSer.decode(resultDcs, yCtx);
175
176 return ((ModelConverter) yangModelRegistry).createModel(compositeData.resourceData());
177 }
178
179 /**
180 * Internal method to generically make a NETCONF edit-config call from a set of YANG objects.
181 *
182 * @param moConfig A YANG object model
183 * @param session A NETCONF session
184 * @param targetDs - running,candidate or startup
185 * @param annotations A list of AnnotatedNodeInfos to be added to the DataNodes
186 * @return Boolean value indicating success or failure of command
187 * @throws NetconfException if the session has any error
188 */
189 protected final boolean setNetconfObject(
190 ModelObjectData moConfig, NetconfSession session, DatastoreId targetDs,
191 List<AnnotatedNodeInfo> annotations) throws NetconfException {
192 if (moConfig == null) {
193 throw new NetconfException("Query object cannot be null");
194 } else if (session == null) {
Sean Condon0e89bda2017-03-21 14:23:19 +0000195 throw new NetconfException("Session is null when calling setNetconfObject()");
Sean Condon06613e92017-06-09 15:14:01 +0100196 } else if (targetDs == null) {
Sean Condon0e89bda2017-03-21 14:23:19 +0000197 throw new NetconfException("TargetDs is null when calling setNetconfObject()");
Sean Condon06613e92017-06-09 15:14:01 +0100198 }
199
200 String xmlQueryStr = encodeMoToXmlStr(moConfig, annotations);
201 log.debug("Sending <edit-config> query on NETCONF session " + session.getSessionId() +
202 ":\n" + xmlQueryStr);
203
Sean Condon0e89bda2017-03-21 14:23:19 +0000204 //Some encoded values just have to be replaced
205 xmlQueryStr = xmlQueryStr.replace(MessagePeriodEnum.YANGAUTOPREFIX3MS.toString(), "3ms");
206 xmlQueryStr = xmlQueryStr.replace(MessagePeriodEnum.YANGAUTOPREFIX10MS.toString(), "10ms");
207 xmlQueryStr = xmlQueryStr.replace(MessagePeriodEnum.YANGAUTOPREFIX100MS.toString(), "100ms");
208 xmlQueryStr = xmlQueryStr.replace(MessagePeriodEnum.YANGAUTOPREFIX1000MS.toString(), "1000ms");
209
210 xmlQueryStr = xmlQueryStr.replace(CcmIntervalEnum.YANGAUTOPREFIX3_3MS.toString(), "3.3ms");
211 xmlQueryStr = xmlQueryStr.replace(CcmIntervalEnum.YANGAUTOPREFIX10MS.toString(), "10ms");
212 xmlQueryStr = xmlQueryStr.replace(CcmIntervalEnum.YANGAUTOPREFIX100MS.toString(), "100ms");
213 xmlQueryStr = xmlQueryStr.replace(CcmIntervalEnum.YANGAUTOPREFIX1S.toString(), "1s");
214
Sean Condon06613e92017-06-09 15:14:01 +0100215 return session.editConfig(targetDs, null, xmlQueryStr);
216 }
217
Sean Condon0e89bda2017-03-21 14:23:19 +0000218 /**
219 * Internal method to generically call a NETCONF custom RPC from a set of YANG objects.
220 *
221 * @param customRpcInput A YANG object model
222 * @param rpcName The name of the RPC - replaces 'input' in the XML payload
223 * @param session A NETCONF session
224 * @return ModelObjectData value indicating success or failure of command
225 * @throws NetconfException if the session has any error
226 */
227 protected final ModelObjectData customRpcNetconf(
228 ModelObjectData customRpcInput, String rpcName, NetconfSession session)
229 throws NetconfException {
230 if (customRpcInput == null) {
231 throw new NetconfException("Input object cannot be null");
232 } else if (session == null) {
233 throw new NetconfException("Session is null when calling customRpcNetconf()");
234 }
235
236 String xmlQueryStr = encodeMoToXmlStr(customRpcInput, null);
237 xmlQueryStr = xmlQueryStr.replace("input", rpcName);
238 log.debug("Sending <edit-config> query on NETCONF session " + session.getSessionId() +
239 ":\n" + xmlQueryStr);
240
241 String xmlResult = session.doWrappedRpc(xmlQueryStr);
242 xmlResult = removeRpcReplyData(xmlResult);
243 if (REGEX_RPC_OK.matcher(xmlResult).matches()) {
244 return null;
245 }
246
247 DefaultCompositeStream resultDcs = new DefaultCompositeStream(
248 null, new ByteArrayInputStream(xmlResult.getBytes()));
249 CompositeData compositeData = xSer.decode(resultDcs, yCtx);
250
251 return ((ModelConverter) yangModelRegistry).createModel(compositeData.resourceData());
252 }
253
Sean Condon06613e92017-06-09 15:14:01 +0100254 protected final String encodeMoToXmlStr(ModelObjectData yangObjectOpParamFilter,
255 List<AnnotatedNodeInfo> annotations)
256 throws NetconfException {
257 //Convert the param to XML to use as a filter
258 ResourceData rd = ((ModelConverter) yangModelRegistry).createDataNode(yangObjectOpParamFilter);
259
260 DefaultCompositeData.Builder cdBuilder =
261 DefaultCompositeData.builder().resourceData(rd);
262 if (annotations != null) {
263 for (AnnotatedNodeInfo ani : annotations) {
264 cdBuilder.addAnnotatedNodeInfo(ani);
265 }
266 }
267 CompositeStream cs = xSer.encode(cdBuilder.build(), yCtx);
268 //Convert the param to XML to use as a filter
269
270 try {
271 ByteSource byteSource = new ByteSource() {
272 @Override
273 public InputStream openStream() throws IOException {
274 return cs.resourceData();
275 }
276 };
277
278 return byteSource.asCharSource(Charsets.UTF_8).read();
279 } catch (IOException e) {
280 throw new NetconfException("Error decoding CompositeStream to String", e);
281 }
282 }
283
Sean Condon0e89bda2017-03-21 14:23:19 +0000284 protected static final String removeRpcReplyData(String rpcReplyXml) throws NetconfException {
Sean Condon06613e92017-06-09 15:14:01 +0100285 rpcReplyXml = REGEX_XML_HEADER.matcher(rpcReplyXml).replaceFirst("");
Sean Condon0e89bda2017-03-21 14:23:19 +0000286 if (rpcReplyXml.contains("<rpc-error")) {
287 throw new NetconfException("NETCONF rpc-error: " + rpcReplyXml);
288 }
289
Sean Condon06613e92017-06-09 15:14:01 +0100290 rpcReplyXml = REGEX_RPC_REPLY.matcher(rpcReplyXml).replaceFirst("");
291 rpcReplyXml = REGEX_RPC_REPLY_DATA_NS.matcher(rpcReplyXml).replaceFirst("");
292 rpcReplyXml = REGEX_RPC_REPLY_DATA.matcher(rpcReplyXml).replaceFirst("");
293 rpcReplyXml = REGEX_RPC_REPLY_DATA_CLOSE.matcher(rpcReplyXml).replaceFirst("");
294 rpcReplyXml = REGEX_RPC_REPLY_DATA_EMPTY.matcher(rpcReplyXml).replaceFirst("");
295 rpcReplyXml = REGEX_RPC_REPLY_CLOSE.matcher(rpcReplyXml).replaceFirst("");
296 rpcReplyXml = rpcReplyXml.replace("\t", "");
297 return rpcReplyXml;
298 }
299}