blob: 074aad4ac64897d8b5d8c4e58ac80bf99ba04bf0 [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
Sean Condon06613e92017-06-09 15:14:01 +010079 protected ApplicationId appId;
80
81 // xSer is not a service and is a class variable. Can be lost on deactivate.
82 // Must be recreated on activate
Sean Condon1dbcd712017-10-19 12:09:21 +010083 protected XmlSerializer xSer = null;
84 protected YangSerializerContext yCtx = null;
Sean Condon06613e92017-06-09 15:14:01 +010085
86 protected static final Pattern REGEX_XML_HEADER =
87 Pattern.compile("(<\\?xml).*(\\?>)", Pattern.DOTALL);
88 protected static final Pattern REGEX_RPC_REPLY =
89 Pattern.compile("(<rpc-reply)[ ]*" +
90 "(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\")[ ]*" +
91 "(message-id=\")[0-9]*(\">)", Pattern.DOTALL);
92 protected static final Pattern REGEX_RPC_REPLY_DATA_NS =
93 Pattern.compile("(<data)[ ]*(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)");
94 protected static final Pattern REGEX_RPC_REPLY_DATA =
95 Pattern.compile("(<data>)");
96 protected static final Pattern REGEX_RPC_REPLY_DATA_CLOSE =
97 Pattern.compile("(</data>)");
98 protected static final Pattern REGEX_RPC_REPLY_DATA_EMPTY =
99 Pattern.compile("(<data/>)");
100 protected static final Pattern REGEX_RPC_REPLY_CLOSE =
101 Pattern.compile("(</rpc-reply>)");
Sean Condon0e89bda2017-03-21 14:23:19 +0000102 protected static final Pattern REGEX_RPC_OK =
103 Pattern.compile("\\R?\\s*(<ok/>)\\R?");
Sean Condon06613e92017-06-09 15:14:01 +0100104 @Activate
105 public void activate() {
106 Set<YangSerializer> yangSer = ((YangSerializerRegistry) yangModelRegistry).getSerializers();
Sean Condon1dbcd712017-10-19 12:09:21 +0100107 xSer = (XmlSerializer) yangSer.stream()
108 .filter(ser -> (ser instanceof XmlSerializer)).findFirst().get();
Sean Condon06613e92017-06-09 15:14:01 +0100109 SchemaContext context = ((SchemaContextProvider) yangModelRegistry)
110 .getSchemaContext(ResourceId.builder().addBranchPointSchema("/", null).build());
111
112 yCtx = new DefaultYangSerializerContext(context, null);
113 };
114
115 @Deactivate
116 public void deactivate() {
117 alreadyLoaded = false;
118 }
119
120 /**
121 * Internal method to generically make a NETCONF get query from YANG objects.
122 * @param moFilter A YANG object model
123 * @param session A NETCONF session
124 * @return YangObjectModel
125 * @throws NetconfException if the session has any error
126 */
127 protected final ModelObjectData getNetconfObject(
128 ModelObjectData moFilter, NetconfSession session)
129 throws NetconfException {
130
131 return getConfigNetconfObject(moFilter, session, null);
132 }
133
134 /**
135 * Internal method to generically make a NETCONF get-config query from YANG objects.
136 *
137 * @param moFilter A YANG object model
138 * @param session A NETCONF session
139 * @param targetDs - running,candidate or startup
140 * @return YangObjectModel
141 * @throws NetconfException if the session has any error
142 */
143 protected final ModelObjectData getConfigNetconfObject(
144 ModelObjectData moFilter, NetconfSession session, DatastoreId targetDs)
145 throws NetconfException {
146 if (session == null) {
147 throw new NetconfException("Session is null when calling getConfigNetconfObject()");
148 }
149
150 if (moFilter == null) {
151 throw new NetconfException("Query object cannot be null");
152 }
153
154 String xmlQueryStr = encodeMoToXmlStr(moFilter, null);
155
156 log.debug("Sending <get-(config)> query on NETCONF session " + session.getSessionId() +
157 ":\n" + xmlQueryStr);
158 String xmlResult;
159 if (targetDs == null) {
160 xmlResult = session.get(xmlQueryStr, null);
161 } else {
162 xmlResult = session.getConfig(targetDs, xmlQueryStr);
163 }
164 xmlResult = removeRpcReplyData(xmlResult);
165
166 DefaultCompositeStream resultDcs = new DefaultCompositeStream(
167 null, new ByteArrayInputStream(xmlResult.getBytes()));
168 CompositeData compositeData = xSer.decode(resultDcs, yCtx);
169
170 return ((ModelConverter) yangModelRegistry).createModel(compositeData.resourceData());
171 }
172
173 /**
174 * Internal method to generically make a NETCONF edit-config call from a set of YANG objects.
175 *
176 * @param moConfig A YANG object model
177 * @param session A NETCONF session
178 * @param targetDs - running,candidate or startup
179 * @param annotations A list of AnnotatedNodeInfos to be added to the DataNodes
180 * @return Boolean value indicating success or failure of command
181 * @throws NetconfException if the session has any error
182 */
183 protected final boolean setNetconfObject(
184 ModelObjectData moConfig, NetconfSession session, DatastoreId targetDs,
185 List<AnnotatedNodeInfo> annotations) throws NetconfException {
186 if (moConfig == null) {
187 throw new NetconfException("Query object cannot be null");
188 } else if (session == null) {
Sean Condon0e89bda2017-03-21 14:23:19 +0000189 throw new NetconfException("Session is null when calling setNetconfObject()");
Sean Condon06613e92017-06-09 15:14:01 +0100190 } else if (targetDs == null) {
Sean Condon0e89bda2017-03-21 14:23:19 +0000191 throw new NetconfException("TargetDs is null when calling setNetconfObject()");
Sean Condon06613e92017-06-09 15:14:01 +0100192 }
193
194 String xmlQueryStr = encodeMoToXmlStr(moConfig, annotations);
195 log.debug("Sending <edit-config> query on NETCONF session " + session.getSessionId() +
196 ":\n" + xmlQueryStr);
197
Sean Condon0e89bda2017-03-21 14:23:19 +0000198 //Some encoded values just have to be replaced
199 xmlQueryStr = xmlQueryStr.replace(MessagePeriodEnum.YANGAUTOPREFIX3MS.toString(), "3ms");
200 xmlQueryStr = xmlQueryStr.replace(MessagePeriodEnum.YANGAUTOPREFIX10MS.toString(), "10ms");
201 xmlQueryStr = xmlQueryStr.replace(MessagePeriodEnum.YANGAUTOPREFIX100MS.toString(), "100ms");
202 xmlQueryStr = xmlQueryStr.replace(MessagePeriodEnum.YANGAUTOPREFIX1000MS.toString(), "1000ms");
203
204 xmlQueryStr = xmlQueryStr.replace(CcmIntervalEnum.YANGAUTOPREFIX3_3MS.toString(), "3.3ms");
205 xmlQueryStr = xmlQueryStr.replace(CcmIntervalEnum.YANGAUTOPREFIX10MS.toString(), "10ms");
206 xmlQueryStr = xmlQueryStr.replace(CcmIntervalEnum.YANGAUTOPREFIX100MS.toString(), "100ms");
207 xmlQueryStr = xmlQueryStr.replace(CcmIntervalEnum.YANGAUTOPREFIX1S.toString(), "1s");
208
Sean Condon06613e92017-06-09 15:14:01 +0100209 return session.editConfig(targetDs, null, xmlQueryStr);
210 }
211
Sean Condon0e89bda2017-03-21 14:23:19 +0000212 /**
213 * Internal method to generically call a NETCONF custom RPC from a set of YANG objects.
214 *
215 * @param customRpcInput A YANG object model
216 * @param rpcName The name of the RPC - replaces 'input' in the XML payload
217 * @param session A NETCONF session
218 * @return ModelObjectData value indicating success or failure of command
219 * @throws NetconfException if the session has any error
220 */
221 protected final ModelObjectData customRpcNetconf(
222 ModelObjectData customRpcInput, String rpcName, NetconfSession session)
223 throws NetconfException {
224 if (customRpcInput == null) {
225 throw new NetconfException("Input object cannot be null");
226 } else if (session == null) {
227 throw new NetconfException("Session is null when calling customRpcNetconf()");
228 }
229
230 String xmlQueryStr = encodeMoToXmlStr(customRpcInput, null);
231 xmlQueryStr = xmlQueryStr.replace("input", rpcName);
232 log.debug("Sending <edit-config> query on NETCONF session " + session.getSessionId() +
233 ":\n" + xmlQueryStr);
234
235 String xmlResult = session.doWrappedRpc(xmlQueryStr);
236 xmlResult = removeRpcReplyData(xmlResult);
237 if (REGEX_RPC_OK.matcher(xmlResult).matches()) {
238 return null;
239 }
240
241 DefaultCompositeStream resultDcs = new DefaultCompositeStream(
242 null, new ByteArrayInputStream(xmlResult.getBytes()));
243 CompositeData compositeData = xSer.decode(resultDcs, yCtx);
244
245 return ((ModelConverter) yangModelRegistry).createModel(compositeData.resourceData());
246 }
247
Sean Condon06613e92017-06-09 15:14:01 +0100248 protected final String encodeMoToXmlStr(ModelObjectData yangObjectOpParamFilter,
249 List<AnnotatedNodeInfo> annotations)
250 throws NetconfException {
251 //Convert the param to XML to use as a filter
252 ResourceData rd = ((ModelConverter) yangModelRegistry).createDataNode(yangObjectOpParamFilter);
253
254 DefaultCompositeData.Builder cdBuilder =
255 DefaultCompositeData.builder().resourceData(rd);
256 if (annotations != null) {
257 for (AnnotatedNodeInfo ani : annotations) {
258 cdBuilder.addAnnotatedNodeInfo(ani);
259 }
260 }
261 CompositeStream cs = xSer.encode(cdBuilder.build(), yCtx);
262 //Convert the param to XML to use as a filter
263
264 try {
265 ByteSource byteSource = new ByteSource() {
266 @Override
267 public InputStream openStream() throws IOException {
268 return cs.resourceData();
269 }
270 };
271
272 return byteSource.asCharSource(Charsets.UTF_8).read();
273 } catch (IOException e) {
274 throw new NetconfException("Error decoding CompositeStream to String", e);
275 }
276 }
277
Sean Condon0e89bda2017-03-21 14:23:19 +0000278 protected static final String removeRpcReplyData(String rpcReplyXml) throws NetconfException {
Sean Condon06613e92017-06-09 15:14:01 +0100279 rpcReplyXml = REGEX_XML_HEADER.matcher(rpcReplyXml).replaceFirst("");
Sean Condon0e89bda2017-03-21 14:23:19 +0000280 if (rpcReplyXml.contains("<rpc-error")) {
281 throw new NetconfException("NETCONF rpc-error: " + rpcReplyXml);
282 }
283
Sean Condon06613e92017-06-09 15:14:01 +0100284 rpcReplyXml = REGEX_RPC_REPLY.matcher(rpcReplyXml).replaceFirst("");
285 rpcReplyXml = REGEX_RPC_REPLY_DATA_NS.matcher(rpcReplyXml).replaceFirst("");
286 rpcReplyXml = REGEX_RPC_REPLY_DATA.matcher(rpcReplyXml).replaceFirst("");
287 rpcReplyXml = REGEX_RPC_REPLY_DATA_CLOSE.matcher(rpcReplyXml).replaceFirst("");
288 rpcReplyXml = REGEX_RPC_REPLY_DATA_EMPTY.matcher(rpcReplyXml).replaceFirst("");
289 rpcReplyXml = REGEX_RPC_REPLY_CLOSE.matcher(rpcReplyXml).replaceFirst("");
290 rpcReplyXml = rpcReplyXml.replace("\t", "");
291 return rpcReplyXml;
292 }
293}