diff --git a/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java b/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java index 8bf6876452..b048744777 100644 --- a/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java +++ b/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java @@ -161,7 +161,7 @@ public class YangModelMessageHandler extends UiMessageHandler { // FIXME: Hack to properly resolve the YANG source resource private InputStream getSource(String modelId, YangModule module) { try { - module.getYangSource(); // trigger exception + return module.getYangSource(); // trigger exception } catch (ModelException e) { // Strip the YANG source file base-name and then use it to access // the corresponding resource in the correct run-time context. @@ -172,7 +172,6 @@ public class YangModelMessageHandler extends UiMessageHandler { return loader == null ? null : loader.getResourceAsStream("/yang/resources" + baseName); } - return null; } private void addSource(ArrayNode source, InputStream yangSource) { diff --git a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel-theme.css b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel-theme.css index c26ade5144..971e133a33 100644 --- a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel-theme.css +++ b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel-theme.css @@ -14,6 +14,11 @@ * limitations under the License. */ +/* -- Drag-n-Drop YANG/ZIP files -- */ +div.dropping { + border: solid 3px #0095d6; +} + .light #yang-model-details-panel .src-frame { background-color: #f4f4f4; } diff --git a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.css b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.css index bf3dce687a..f65e6366ae 100644 --- a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.css +++ b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.css @@ -14,11 +14,23 @@ * limitations under the License. */ - #ov-yang-model h2 { display: inline-block; } +#ov-yang-model div.ctrl-btns { + width: 250px; +} + +/* -- Drag-n-Drop file upload -- */ +#ov-yang-model form#inputYangFileForm, +#ov-yang-model input#uploadYangFile { + display: none; +} + +.dropping { + +} #yang-model-details-panel.floatpanel { z-index: 0; diff --git a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.html b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.html index b49bcd8d8a..6cbb0e1887 100644 --- a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.html +++ b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.html @@ -1,5 +1,5 @@ -
+

YANG Models ({{tableData.length}} total)

@@ -8,6 +8,19 @@ icon icon-id="refresh" icon-size="42" tooltip tt-msg="autoRefreshTip" ng-click="toggleRefresh()">
+ +
+ +
+ +
+ +
+
diff --git a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js index 00b66439b7..42fa343135 100644 --- a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js +++ b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js @@ -44,7 +44,8 @@ // constants var pName = 'yang-model-details-panel', detailsReq = 'yangModelDetailsRequest', - detailsResp = 'yangModelDetailsResponse'; + detailsResp = 'yangModelDetailsResponse', + fileUploadUrl = '/onos/yang/models?modelId='; function createDetailsPanel() { @@ -135,11 +136,12 @@ // defines view controller angular.module('ovYangModel', []) .controller('OvYangModelCtrl', [ - '$log', '$scope', 'TableBuilderService', 'TableDetailService', + '$log', '$scope', '$http', '$timeout', + 'TableBuilderService', 'TableDetailService', 'FnService', 'MastService', 'PanelService', 'WebSocketService', - 'IconService', + 'IconService', 'UrlFnService', 'FlashService', - function (_$log_, _$scope_, tbs, tds, _fs_, _mast_, _ps_, _wss_, _is_) { + function (_$log_, _$scope_, $http, $timeout, tbs, tds, _fs_, _mast_, _ps_, _wss_, _is_, ufs, _flash_) { var handlers = {}; $log = _$log_; @@ -176,6 +178,45 @@ selCb: selCb }); + $scope.$on('YangFileChanged', function () { + var formData = new FormData(), + url, modelId, finished = false; + + if ($scope.yangFile) { + modelId = $scope.yangFile.name; + modelId = modelId.substr(0, modelId.lastIndexOf(".")); + url = fileUploadUrl + modelId; + formData.append('file', $scope.yangFile); + $log.info('Compiling', $scope.yangFile); + d3.select('#frame').classed('dropping', false); + + // FIXME: Replace this with dialog that shows progress... + for (var i = 0; i < 10; i++) { + $timeout(function () { + if (!finished) _flash_.flash('Compiling ' + modelId); + }, i * 1100); + } + + $http.post(url, formData, { + transformRequest: angular.identity, + headers: { + 'Content-Type': undefined + } + }) + .finally(function () { + finished = true; + _flash_.flash('Compile completed for ' + modelId); + $scope.sortCallback($scope.sortParams); + document.getElementById('inputYangFileForm').reset(); + }); + } + }); + + $scope.yangDropped = function() { + $scope.$emit('YangFileChanged'); + $scope.yangFile = null; + }; + $scope.$on('$destroy', function () { wss.unbindHandlers(handlers); }); @@ -184,6 +225,78 @@ } ]) + // triggers the input form to appear when button is clicked + .directive('triggerYangForm', function () { + return { + restrict: 'A', + link: function (scope, elem) { + elem.bind('click', function () { + document.getElementById('uploadYangFile') + .dispatchEvent(new MouseEvent('click')); + }); + } + }; + }) + + // binds the model file to the scope in scope.yangFile + // sends upload request to the server + .directive('yangFileModel', ['$parse', + function ($parse) { + return { + restrict: 'A', + link: function (scope, elem, attrs) { + var model = $parse(attrs.yangFileModel), + modelSetter = model.assign; + + elem.bind('change', function () { + scope.$apply(function () { + modelSetter(scope, elem[0].files[0]); + }); + scope.$emit('YangFileChanged'); + }); + } + }; + } + ]) + + .directive("yangfiledrop", ['$parse', '$document', function ($parse, $document) { + return { + restrict: "A", + link: function (scope, element, attrs) { + var onYangDrop = $parse(attrs.onFileDrop); + + // When an item is dragged over the document + var onDragOver = function (e) { + d3.select('#frame').classed('dropping', true); + e.preventDefault(); + }; + + // When the user leaves the window, cancels the drag or drops the item + var onDragEnd = function (e) { + d3.select('#frame').classed('dropping', false); + e.preventDefault(); + }; + + // When a file is dropped + var loadFile = function (file) { + scope.yangFile = file; + scope.$apply(onYangDrop(scope)); + }; + + // Dragging begins on the document + $document.bind("dragover", onDragOver); + + // Dragging ends on the overlay, which takes the whole window + element.bind("dragleave", onDragEnd) + .bind("drop", function (e) { + $log.info('Drag leave', e); + loadFile(e.dataTransfer.files[0]); + onDragEnd(e); + }); + } + }; + }]) + .directive('yangModelDetailsPanel', [ '$rootScope', '$window', '$timeout', 'KeyService', diff --git a/apps/yang/src/main/java/org/onosproject/yang/YangLiveCompilerManager.java b/apps/yang/src/main/java/org/onosproject/yang/YangLiveCompilerManager.java deleted file mode 100644 index a4fc857a1c..0000000000 --- a/apps/yang/src/main/java/org/onosproject/yang/YangLiveCompilerManager.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.yang; - -import com.google.common.annotations.Beta; -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.onosproject.core.CoreService; -import org.onosproject.yang.compiler.api.YangCompilationParam; -import org.onosproject.yang.compiler.api.YangCompiledOutput; -import org.onosproject.yang.compiler.api.YangCompilerException; -import org.onosproject.yang.compiler.api.YangCompilerService; -import org.onosproject.yang.compiler.tool.YangCompilerManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; - -/** - * Represents implementation of YANG live compiler manager. - */ -@Beta -@Service -@Component(immediate = true) -public class YangLiveCompilerManager implements YangCompilerService { - - private static final String APP_ID = "org.onosproject.yang"; - private final Logger log = LoggerFactory.getLogger(getClass()); - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected CoreService coreService; - - @Activate - public void activate() { - coreService.registerApplication(APP_ID); - log.info("Started"); - } - - @Deactivate - public void deactivate() { - log.info("Stopped"); - } - - @Override - public YangCompiledOutput compileYangFiles(YangCompilationParam param) - throws IOException, YangCompilerException { - return new YangCompilerManager().compileYangFiles(param); - } -} diff --git a/apps/yang/src/main/java/org/onosproject/yang/YangLiveCompilerService.java b/apps/yang/src/main/java/org/onosproject/yang/YangLiveCompilerService.java new file mode 100644 index 0000000000..de151d1d12 --- /dev/null +++ b/apps/yang/src/main/java/org/onosproject/yang/YangLiveCompilerService.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017-present Open Networking Foundation + * + * 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.yang; + +import com.google.common.annotations.Beta; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Runtime service for compiling YANG source files and packaging the compiled + * artifacts into a ready-to-load application. + */ +@Beta +public interface YangLiveCompilerService { + + /** + * Compiles the YANG source file(s) contained in the specified input + * stream either as individual YANG source file, or as a JAR/ZIP collection + * of YANG source files. + * + * @param modelId model identifier + * @param yangSources input stream containing a single YANG source file + * or a JAR/ZIP archive containing collection of YANG + * source files + * @return input stream containing a packaged ONOS application JAR file + * @throws IOException if issues arise when reading the yang sources stream + */ + InputStream compileYangFiles(String modelId, InputStream yangSources) throws IOException; + +} diff --git a/apps/yang/src/main/java/org/onosproject/yang/impl/YangCompileCommand.java b/apps/yang/src/main/java/org/onosproject/yang/impl/YangCompileCommand.java new file mode 100644 index 0000000000..3061da6d4f --- /dev/null +++ b/apps/yang/src/main/java/org/onosproject/yang/impl/YangCompileCommand.java @@ -0,0 +1,80 @@ +/* + * Copyright 2017-present Open Networking Foundation + * + * 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.yang.impl; + +import com.google.common.io.ByteStreams; +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.app.ApplicationAdminService; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.ApplicationId; +import org.onosproject.yang.YangLiveCompilerService; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +/** + * Compiles the provided YANG source files and installs the resulting model extension. + */ +@Command(scope = "onos", name = "compile-model", + description = "Compiles the provided YANG source files and installs the resulting model extension") +public class YangCompileCommand extends AbstractShellCommand { + + @Option(name = "-c", aliases = "--compile-only", + description = "Only compile, but do not install the model") + private boolean compileOnly = false; + + @Option(name = "-f", aliases = "--force", + description = "Force reinstall if already installed") + private boolean forceReinstall = false; + + @Argument(index = 0, name = "modelId", + description = "Model ID", required = true) + String modelId = null; + + @Argument(index = 1, name = "url", + description = "URL to the YANG source file(s); .yang, .zip or .jar file", + required = true) + String url = null; + + @Override + protected void execute() { + try { + InputStream yangJar = new URL(url).openStream(); + YangLiveCompilerService compiler = get(YangLiveCompilerService.class); + if (compileOnly) { + ByteStreams.copy(compiler.compileYangFiles(modelId, yangJar), System.out); + } else { + ApplicationAdminService appService = get(ApplicationAdminService.class); + + if (forceReinstall) { + ApplicationId appId = appService.getId(modelId); + if (appId != null && appService.getApplication(appId) != null) { + appService.uninstall(appId); + } + } + + appService.install(compiler.compileYangFiles(modelId, yangJar)); + appService.activate(appService.getId(modelId)); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/apps/yang/src/main/java/org/onosproject/yang/impl/YangLiveCompilerManager.java b/apps/yang/src/main/java/org/onosproject/yang/impl/YangLiveCompilerManager.java new file mode 100644 index 0000000000..d109dc3ded --- /dev/null +++ b/apps/yang/src/main/java/org/onosproject/yang/impl/YangLiveCompilerManager.java @@ -0,0 +1,232 @@ +/* + * Copyright 2017-present Open Networking Foundation + * + * 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.yang.impl; + +import com.google.common.io.ByteStreams; +import com.google.common.io.Files; +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.Service; +import org.onosproject.yang.YangLiveCompilerService; +import org.onosproject.yang.compiler.tool.DefaultYangCompilationParam; +import org.onosproject.yang.compiler.tool.YangCompilerManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import static com.google.common.io.ByteStreams.toByteArray; +import static com.google.common.io.Files.createParentDirs; +import static com.google.common.io.Files.write; +import static java.nio.file.Files.walkFileTree; + +/** + * Represents implementation of YANG live compiler manager. + */ +@Service +@Component(immediate = true) +public class YangLiveCompilerManager implements YangLiveCompilerService { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String ZIP_MAGIC = "PK"; + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public InputStream compileYangFiles(String modelId, + InputStream yangSources) throws IOException { + // Generate temporary directory where the work will happen. + File root = Files.createTempDir(); + log.info("Compiling YANG model to {}", root); + + // Unpack the input stream + File yangRoot = unpackYangSources(root, yangSources); + + // Run the YANG compilation phase + File javaRoot = runYangCompiler(root, yangRoot, modelId); + + // Run the Java compilation phase + File classRoot = runJavaCompiler(root, javaRoot, modelId); + + // Run the JAR assembly phase + File jarFile = runJarAssembly(root, classRoot, modelId); + + // Return the final JAR file as input stream + return new FileInputStream(jarFile); + } + + // Unpacks the given input stream into the YANG root subdirectory of the specified root directory. + private File unpackYangSources(File root, InputStream yangSources) throws IOException { + File yangRoot = new File(root, "yang/"); + if (yangRoot.mkdirs()) { + // Unpack the yang sources into the newly created directory + byte[] cache = toByteArray(yangSources); + InputStream bis = new ByteArrayInputStream(cache); + if (isZipArchive(cache)) { + extractZipArchive(yangRoot, bis); + } else { + extractYangFile(yangRoot, bis); + } + return yangRoot; + } + throw new IOException("Unable to create yang source root"); + } + + // Extracts the YANG source stream into the specified directory. + private void extractYangFile(File dir, InputStream stream) throws IOException { + ByteStreams.copy(stream, new FileOutputStream(new File(dir, "model.yang"))); + } + + // Extracts the ZIP stream into the specified directory. + private void extractZipArchive(File dir, InputStream stream) throws IOException { + ZipInputStream zis = new ZipInputStream(stream); + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + if (!entry.isDirectory()) { + byte[] data = toByteArray(zis); + zis.closeEntry(); + File file = new File(dir, entry.getName()); + createParentDirs(file); + write(data, file); + } + } + zis.close(); + } + + // Runs the YANG compiler on the YANG sources in the specified directory. + private File runYangCompiler(File root, File yangRoot, String modelId) throws IOException { + File javaRoot = new File(root, "java/"); + if (javaRoot.mkdirs()) { + // Prepare the compilation parameter + DefaultYangCompilationParam.Builder param = DefaultYangCompilationParam.builder() + .setCodeGenDir(new File(javaRoot, "src").toPath()) + .setMetadataGenDir(new File(javaRoot, "schema").toPath()) + .setModelId(modelId); + + // TODO: How to convey YANG dependencies? "/dependencies" directory? + + // Iterate over all files and add all YANG sources. + walkFileTree(Paths.get(yangRoot.getAbsolutePath()), + new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) + throws IOException { + if (attributes.isRegularFile() && file.toString().endsWith(".yang")) { + param.addYangFile(file); + } + return FileVisitResult.CONTINUE; + } + }); + + // Run the YANG compiler and collect the results + new YangCompilerManager().compileYangFiles(param.build()); + return javaRoot; + } + throw new IOException("Unable to create Java results root"); + } + + // Runs the Java compilation on the Java sources generated by YANG compiler. + private File runJavaCompiler(File root, File javaRoot, String modelId) throws IOException { + File classRoot = new File(root, "classes/"); + if (classRoot.mkdirs()) { + File compilerScript = writeResource("onos-yang-javac", root); + writeResource("YangModelRegistrator.java", root); + execute(new String[]{ + "bash", + compilerScript.getAbsolutePath(), + javaRoot.getAbsolutePath(), + classRoot.getAbsolutePath(), + modelId + }); + return classRoot; + } + throw new IOException("Unable to create class results root"); + } + + // Run the JAR assembly on the classes root and include any YANG sources as well. + private File runJarAssembly(File root, File classRoot, String modelId) throws IOException { + File jarFile = new File(root, "model.jar"); + File jarScript = writeResource("onos-yang-jar", root); + writeResource("app.xml", root); + writeResource("features.xml", root); + writeResource("YangModelRegistrator.xml", root); + execute(new String[]{ + "bash", + jarScript.getAbsolutePath(), + classRoot.getAbsolutePath(), + jarFile.getAbsolutePath(), + modelId + }); + return jarFile; + } + + // Writes the specified resource as a file in the given directory. + private File writeResource(String resourceName, File dir) throws IOException { + File script = new File(dir, resourceName); + write(toByteArray(getClass().getResourceAsStream("/" + resourceName)), script); + return script; + } + + // Indicates whether the stream encoded in the given bytes is a ZIP archive. + private boolean isZipArchive(byte[] bytes) { + return substring(bytes, ZIP_MAGIC.length()).equals(ZIP_MAGIC); + } + + // Returns the substring of maximum possible length from the specified bytes. + private String substring(byte[] bytes, int length) { + return new String(bytes, 0, Math.min(bytes.length, length), StandardCharsets.UTF_8); + } + + // Executes the given command arguments as a system command. + private void execute(String[] command) throws IOException { + try { + Process process = Runtime.getRuntime().exec(command); + byte[] output = toByteArray(process.getInputStream()); + byte[] error = toByteArray(process.getErrorStream()); + int code = process.waitFor(); + if (code != 0) { + log.info("Command failed: status={}, output={}, error={}", + code, new String(output), new String(error)); + } + } catch (InterruptedException e) { + log.error("Interrupted executing command {}", command, e); + } + } +} diff --git a/apps/yang/src/main/java/org/onosproject/yang/YangModelsListCommand.java b/apps/yang/src/main/java/org/onosproject/yang/impl/YangModelsListCommand.java similarity index 79% rename from apps/yang/src/main/java/org/onosproject/yang/YangModelsListCommand.java rename to apps/yang/src/main/java/org/onosproject/yang/impl/YangModelsListCommand.java index 5915e882b5..69fef62f2a 100644 --- a/apps/yang/src/main/java/org/onosproject/yang/YangModelsListCommand.java +++ b/apps/yang/src/main/java/org/onosproject/yang/impl/YangModelsListCommand.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.yang; +package org.onosproject.yang.impl; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -29,11 +29,11 @@ import org.onosproject.yang.runtime.YangModelRegistry; * Lists registered YANG models. */ @Command(scope = "onos", name = "models", - description = "Lists registered YANG models") + description = "Lists registered YANG models") public class YangModelsListCommand extends AbstractShellCommand { - private static final String FORMAT = "moduleName=%s moduleRevision=%s modelId=%s"; + private static final String FORMAT = "modelId=%s moduleName=%s moduleRevision=%s"; private static final String MODULE_NAME = "moduleName"; private static final String MODULE_REVISION = "moduleRevision"; @@ -44,11 +44,11 @@ public class YangModelsListCommand extends AbstractShellCommand { if (outputJson()) { print("%s", json(service)); } else { - for (YangModel model: service.getModels()) { + for (YangModel model : service.getModels()) { for (YangModule module : model.getYangModules()) { - print(FORMAT, module.getYangModuleId().moduleName(), - module.getYangModuleId().revision(), - modelId(model)); + print(FORMAT, model.getYangModelId(), + module.getYangModuleId().moduleName(), + module.getYangModuleId().revision()); } } } @@ -58,9 +58,9 @@ public class YangModelsListCommand extends AbstractShellCommand { private JsonNode json(YangModelRegistry service) { ObjectMapper mapper = new ObjectMapper(); ObjectNode result = mapper.createObjectNode(); - for (YangModel model: service.getModels()) { + for (YangModel model : service.getModels()) { ArrayNode modelNode = mapper.createArrayNode(); - result.set(modelId(model), modelNode); + result.set(model.getYangModelId(), modelNode); for (YangModule module : model.getYangModules()) { ObjectNode moduleNode = mapper.createObjectNode(); modelNode.add(moduleNode); @@ -71,7 +71,4 @@ public class YangModelsListCommand extends AbstractShellCommand { return result; } - private String modelId(YangModel m) { - return "YM" + Math.abs(m.hashCode()); - } } diff --git a/apps/yang/src/main/java/org/onosproject/yang/YangRuntimeManager.java b/apps/yang/src/main/java/org/onosproject/yang/impl/YangRuntimeManager.java similarity index 98% rename from apps/yang/src/main/java/org/onosproject/yang/YangRuntimeManager.java rename to apps/yang/src/main/java/org/onosproject/yang/impl/YangRuntimeManager.java index b9ac2e148f..5d9a076951 100644 --- a/apps/yang/src/main/java/org/onosproject/yang/YangRuntimeManager.java +++ b/apps/yang/src/main/java/org/onosproject/yang/impl/YangRuntimeManager.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package org.onosproject.yang; +package org.onosproject.yang.impl; -import com.google.common.annotations.Beta; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -24,6 +23,7 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onosproject.core.CoreService; +import org.onosproject.yang.YangClassLoaderRegistry; import org.onosproject.yang.model.ModelConverter; import org.onosproject.yang.model.ModelObjectData; import org.onosproject.yang.model.NodeKey; @@ -62,7 +62,6 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Represents implementation of YANG runtime manager. */ -@Beta @Service @Component(immediate = true) public class YangRuntimeManager implements YangModelRegistry, diff --git a/apps/yang/src/main/java/org/onosproject/yang/impl/package-info.java b/apps/yang/src/main/java/org/onosproject/yang/impl/package-info.java new file mode 100755 index 0000000000..514024867c --- /dev/null +++ b/apps/yang/src/main/java/org/onosproject/yang/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-present Open Networking Foundation + * + * 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. + */ + +/** + * Implementations of various YANG runtime services. + */ +package org.onosproject.yang.impl; \ No newline at end of file diff --git a/apps/yang/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/yang/src/main/resources/OSGI-INF/blueprint/shell-config.xml index 05cb393f98..d5e1711b74 100644 --- a/apps/yang/src/main/resources/OSGI-INF/blueprint/shell-config.xml +++ b/apps/yang/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -16,7 +16,10 @@ - + + + + diff --git a/apps/yang/src/main/resources/YangModelRegistrator.java b/apps/yang/src/main/resources/YangModelRegistrator.java new file mode 100644 index 0000000000..fb6b0e344f --- /dev/null +++ b/apps/yang/src/main/resources/YangModelRegistrator.java @@ -0,0 +1,10 @@ +// Auto-generated code +package PACKAGE; + +import org.onosproject.yang.AbstractYangModelRegistrator; + +public class YangModelRegistrator extends AbstractYangModelRegistrator { + public YangModelRegistrator() { + super(YangModelRegistrator.class); + } +} \ No newline at end of file diff --git a/apps/yang/src/main/resources/YangModelRegistrator.xml b/apps/yang/src/main/resources/YangModelRegistrator.xml new file mode 100644 index 0000000000..647ae45dba --- /dev/null +++ b/apps/yang/src/main/resources/YangModelRegistrator.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/apps/yang/src/main/resources/app.xml b/apps/yang/src/main/resources/app.xml new file mode 100644 index 0000000000..1188a02222 --- /dev/null +++ b/apps/yang/src/main/resources/app.xml @@ -0,0 +1,8 @@ + + + YANG Model: MODEL_ID + mvn:org.onosproject/MODEL_ID/1.0 + \ No newline at end of file diff --git a/apps/yang/src/main/resources/features.xml b/apps/yang/src/main/resources/features.xml new file mode 100644 index 0000000000..7d56a536e8 --- /dev/null +++ b/apps/yang/src/main/resources/features.xml @@ -0,0 +1,9 @@ + + + + onos-api + wrap:mvn:org.onosproject/MODEL_ID/1.0$Bundle-SymbolicName=MODEL_ID&Bundle-Version=1.0&Service-Component=OSGI-INF/MODEL_ID.YangModelRegistrator.xml + + \ No newline at end of file diff --git a/apps/yang/src/main/resources/onos-yang-jar b/apps/yang/src/main/resources/onos-yang-jar new file mode 100644 index 0000000000..4429e07600 --- /dev/null +++ b/apps/yang/src/main/resources/onos-yang-jar @@ -0,0 +1,24 @@ +#!/bin/bash +# ----------------------------------------------------------------------------- +# Assembles ONOS application jar from the compiled YANG model artifacts. +# ----------------------------------------------------------------------------- + +classes=${1:-classes} +jar=${2:-model.jar} +modelId=${3-org.onosproject.model.unknown} + +# Generate the app.xml descriptor file and stage it at the top of the jar +sed "s/MODEL_ID/$modelId/g" $(dirname $0)/app.xml > $classes/app.xml + +# Generate features.xml file and stage it at the top of the jar +sed "s/MODEL_ID/$modelId/g" $(dirname $0)/features.xml > $classes/features.xml +mkdir -p $classes/m2/org/onosproject/$modelId/1.0/ +cp $classes/features.xml $classes/m2/org/onosproject/$modelId/1.0/$modelId-1.0-features.xml + +# Generate model self-registrator SCR descriptor +mkdir -p $classes/OSGI-INF +sed "s/PACKAGE/$modelId/g" $(dirname $0)/YangModelRegistrator.xml \ + > $classes/OSGI-INF/$modelId.YangModelRegistrator.xml + +cd $classes +jar cf $jar * \ No newline at end of file diff --git a/apps/yang/src/main/resources/onos-yang-javac b/apps/yang/src/main/resources/onos-yang-javac new file mode 100755 index 0000000000..1fa344c9a3 --- /dev/null +++ b/apps/yang/src/main/resources/onos-yang-javac @@ -0,0 +1,35 @@ +#!/bin/bash +# ----------------------------------------------------------------------------- +# Compiles Java code generated by the YANG compiler. +# ----------------------------------------------------------------------------- + +sources=${1:-src} +classes=${2:-classes} +modelId=${3:-org.onosproject.model.unknown} + +# Stage the YANG sources and the YANG schema meta-data +mkdir -p $classes/yang/resources +cp $sources/schema/* $classes/yang/resources + +root=${root:-system} +op="$root/org/onosproject" + +function findLib() { + find $1/$2 -name "$2-*.jar" +} + +classPath="$(findLib $op onos-yang-model)" +classPath="$classPath:$(findLib $op onos-yang-runtime)" +classPath="$classPath:$(findLib $op onos-yang-compiler-api)" +classPath="$classPath:$(findLib $op onos-apps-yang)" + +package=${modelId//./\/} +mkdir -p $sources/src/$package +sed "s/PACKAGE/$modelId/g" $(dirname $0)/YangModelRegistrator.java \ + > $sources/src/$package/YangModelRegistrator.java + +# Compile the generated java code +find $sources/src -name '*.java' > $sources/javaFiles +javac -source 1.8 -target 1.8 \ + -sourcepath "$sources/src" -classpath "$classPath" -d "$classes" \ + @$sources/javaFiles diff --git a/apps/yang/web/BUCK b/apps/yang/web/BUCK index e6a782f045..95637658a0 100644 --- a/apps/yang/web/BUCK +++ b/apps/yang/web/BUCK @@ -6,6 +6,7 @@ COMPILE_DEPS = [ '//lib:onos-yang-model', '//lib:onos-yang-compiler-api', '//lib:onos-yang-runtime', + '//apps/yang:onos-apps-yang' ] TEST_DEPS = [ diff --git a/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebResource.java b/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebResource.java index 72d9cbe9dd..9e56f4a3ce 100644 --- a/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebResource.java +++ b/apps/yang/web/src/main/java/org/onosproject/yang/web/YangWebResource.java @@ -20,7 +20,10 @@ import org.apache.commons.io.IOUtils; import org.glassfish.jersey.media.multipart.FormDataBodyPart; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.glassfish.jersey.media.multipart.FormDataParam; +import org.onosproject.app.ApplicationAdminService; import org.onosproject.rest.AbstractWebResource; +import org.onosproject.yang.YangLiveCompilerService; import org.onosproject.yang.compiler.api.YangCompilationParam; import org.onosproject.yang.compiler.api.YangCompilerService; import org.onosproject.yang.compiler.datamodel.YangNode; @@ -32,8 +35,10 @@ import org.onosproject.yang.runtime.ModelRegistrationParam; import org.onosproject.yang.runtime.YangModelRegistry; import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; import javax.ws.rs.POST; import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.File; @@ -71,6 +76,25 @@ public class YangWebResource extends AbstractWebResource { "or unregister."; private static final String SLASH = "/"; + /** + * Compiles and registers the given yang files. + * + * @param modelId model identifier + * @param stream YANG, ZIP or JAR file + * @return 200 OK + * @throws IOException when fails to generate a file + */ + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response upload(@QueryParam("modelId") @DefaultValue("org.onosproject.model.unknown") String modelId, + @FormDataParam("file") InputStream stream) throws IOException { + YangLiveCompilerService compiler = get(YangLiveCompilerService.class); + ApplicationAdminService appService = get(ApplicationAdminService.class); + appService.install(compiler.compileYangFiles(modelId, stream)); + appService.activate(appService.getId(modelId)); + return Response.ok().build(); + } + /** * Compiles and registers the given yang files. * @@ -79,6 +103,7 @@ public class YangWebResource extends AbstractWebResource { * @throws IOException when fails to generate a file */ @POST + @Path("deprecated") @Consumes(MediaType.MULTIPART_FORM_DATA) public Response upload(FormDataMultiPart formData) throws IOException { Map> input = parseInputData(formData); @@ -161,7 +186,7 @@ public class YangWebResource extends AbstractWebResource { } private void addToParam(DefaultYangCompilationParam.Builder builder, - File file) { + File file) { if (file.getName().endsWith(YANG_FILE_EXTENSION)) { builder.addYangFile(Paths.get(file.getAbsolutePath())); } else if (file.getName().endsWith(SER_FILE_EXTENSION)) { @@ -198,8 +223,7 @@ public class YangWebResource extends AbstractWebResource { // first get all directories, // then make those directory on the destination Path - for (Enumeration enums = zip.entries(); - enums.hasMoreElements();) { + for (Enumeration enums = zip.entries(); enums.hasMoreElements();) { ZipEntry entry = enums.nextElement(); String fileName = YANG_RESOURCES + entry.getName(); @@ -211,8 +235,7 @@ public class YangWebResource extends AbstractWebResource { } //now create all files - for (Enumeration enums = zip.entries(); - enums.hasMoreElements();) { + for (Enumeration enums = zip.entries(); enums.hasMoreElements();) { ZipEntry entry = enums.nextElement(); String fileName = YANG_RESOURCES + entry.getName(); File f = new File(fileName); diff --git a/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java b/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java index b02d33ad06..ec386076ab 100644 --- a/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java +++ b/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java @@ -262,6 +262,9 @@ public class ApplicationArchive public synchronized InputStream getApplicationInputStream(String appName) { try { File appFile = appFile(appName, appName + OAR); + if (!appFile.exists()) { + appFile = appFile(appName, appName + JAR); + } return new FileInputStream(appFile.exists() ? appFile : appFile(appName, APP_XML)); } catch (FileNotFoundException e) { throw new ApplicationException("Application " + appName + " not found"); @@ -383,7 +386,7 @@ public class ApplicationArchive // Create the file directory structure and copy the file there. File jar = appFile(desc.name(), jarName); - boolean ok = jar.getParentFile().mkdirs(); + boolean ok = jar.getParentFile().exists() || jar.getParentFile().mkdirs(); if (ok) { Files.write(toByteArray(stream), jar); Files.copy(appFile(desc.name(), FEATURES_XML), appFile(desc.name(), featuresName)); @@ -402,7 +405,9 @@ public class ApplicationArchive cfg.setAttributeSplittingDisabled(true); cfg.setDelimiterParsingDisabled(true); cfg.load(appFile(desc.name(), FEATURES_XML)); - return cfg.getString("feature.bundle"); + return cfg.getString("feature.bundle") + .replaceFirst("wrap:", "") + .replaceFirst("\\$Bundle-.*$", ""); } catch (ConfigurationException e) { log.warn("Self-contained application {} has no features.xml", desc.name()); return null; diff --git a/lib/BUCK b/lib/BUCK index ef2479635f..1013dcff0e 100644 --- a/lib/BUCK +++ b/lib/BUCK @@ -1,4 +1,4 @@ -# ***** This file was auto-generated at Mon, 31 Jul 2017 23:06:54 GMT. Do not edit this file manually. ***** +# ***** This file was auto-generated at Tue, 8 Aug 2017 17:39:19 GMT. Do not edit this file manually. ***** # ***** Use onos-lib-gen ***** pass_thru_pom( @@ -1211,55 +1211,55 @@ remote_jar ( remote_jar ( name = 'onos-yang-model', - out = 'onos-yang-model-2.2.0-b3.jar', - url = 'mvn:org.onosproject:onos-yang-model:jar:2.2.0-b3', - sha1 = '27e93661796c37268a09aa5c4cdc2e2f6e0ec975', - maven_coords = 'org.onosproject:onos-yang-model:2.2.0-b3', + out = 'onos-yang-model-2.2.0-b4.jar', + url = 'mvn:org.onosproject:onos-yang-model:jar:2.2.0-b4', + sha1 = 'a1ebb2e81770b2c55cfc2fd9f6e935403bf329b7', + maven_coords = 'org.onosproject:onos-yang-model:2.2.0-b4', visibility = [ 'PUBLIC' ], ) remote_jar ( name = 'onos-yang-compiler-api', - out = 'onos-yang-compiler-api-2.2.0-b3.jar', - url = 'mvn:org.onosproject:onos-yang-compiler-api:jar:2.2.0-b3', - sha1 = 'eeb41cec4779b3a03c684af4fd176711ba3d999f', - maven_coords = 'org.onosproject:onos-yang-compiler-api:2.2.0-b3', + out = 'onos-yang-compiler-api-2.2.0-b4.jar', + url = 'mvn:org.onosproject:onos-yang-compiler-api:jar:2.2.0-b4', + sha1 = 'b0d7f8569dc14c2444c20b32aebc133be4b31719', + maven_coords = 'org.onosproject:onos-yang-compiler-api:2.2.0-b4', visibility = [ 'PUBLIC' ], ) remote_jar ( name = 'onos-yang-runtime', - out = 'onos-yang-runtime-2.2.0-b3.jar', - url = 'mvn:org.onosproject:onos-yang-runtime:jar:2.2.0-b3', - sha1 = '40dc7df958b5b7779425522c0ac5dccd7c90f325', - maven_coords = 'org.onosproject:onos-yang-runtime:2.2.0-b3', + out = 'onos-yang-runtime-2.2.0-b4.jar', + url = 'mvn:org.onosproject:onos-yang-runtime:jar:2.2.0-b4', + sha1 = '82eeb6c0ecd3e9181f08e6309364e008efd90c73', + maven_coords = 'org.onosproject:onos-yang-runtime:2.2.0-b4', visibility = [ 'PUBLIC' ], ) remote_jar ( name = 'onos-yang-serializers-json', - out = 'onos-yang-serializers-json-2.2.0-b3.jar', - url = 'mvn:org.onosproject:onos-yang-serializers-json:jar:2.2.0-b3', - sha1 = 'c922e6caf738debf3c82a5e950150dcee3691a68', - maven_coords = 'org.onosproject:onos-yang-serializers-json:2.2.0-b3', + out = 'onos-yang-serializers-json-2.2.0-b4.jar', + url = 'mvn:org.onosproject:onos-yang-serializers-json:jar:2.2.0-b4', + sha1 = 'ca24ff1719a3a546220b5a5346d8602fd955026c', + maven_coords = 'org.onosproject:onos-yang-serializers-json:2.2.0-b4', visibility = [ 'PUBLIC' ], ) remote_jar ( name = 'onos-yang-serializers-xml', - out = 'onos-yang-serializers-xml-2.2.0-b3.jar', - url = 'mvn:org.onosproject:onos-yang-serializers-xml:jar:2.2.0-b3', - sha1 = '941c0f451f77f4eeb87f34bb4f8c7c95fab558b2', - maven_coords = 'org.onosproject:onos-yang-serializers-xml:2.2.0-b3', + out = 'onos-yang-serializers-xml-2.2.0-b4.jar', + url = 'mvn:org.onosproject:onos-yang-serializers-xml:jar:2.2.0-b4', + sha1 = '0ecfff253688a2d11574e34f3edf14a8bef25790', + maven_coords = 'org.onosproject:onos-yang-serializers-xml:2.2.0-b4', visibility = [ 'PUBLIC' ], ) remote_jar ( name = 'onos-yang-serializers-utils', - out = 'onos-yang-serializers-utils-2.2.0-b3.jar', - url = 'mvn:org.onosproject:onos-yang-serializers-utils:jar:2.2.0-b3', - sha1 = 'a46292313584ff174b3a7feb998d54253bbb7383', - maven_coords = 'org.onosproject:onos-yang-serializers-utils:2.2.0-b3', + out = 'onos-yang-serializers-utils-2.2.0-b4.jar', + url = 'mvn:org.onosproject:onos-yang-serializers-utils:jar:2.2.0-b4', + sha1 = 'e48c4b374fce66defa1fbe23e9d60e3e78cb48de', + maven_coords = 'org.onosproject:onos-yang-serializers-utils:2.2.0-b4', visibility = [ 'PUBLIC' ], ) diff --git a/lib/deps.json b/lib/deps.json index eacea31706..5dd2f70be5 100644 --- a/lib/deps.json +++ b/lib/deps.json @@ -24,7 +24,7 @@ "slf4j-api", "osgi-core", "org.osgi.compendium", - { "name": "org.apache.felix.scr.annotations", "compile_only": true }, + "org.apache.felix.scr.annotations", "org.apache.felix.scr", "jackson-annotations", "jackson-core", @@ -231,12 +231,12 @@ "onos-yang-datamodel": "mvn:org.onosproject:onos-yang-datamodel:1.11", "onos-yang-maven-plugin": "mvn:org.onosproject:onos-yang-maven-plugin:1.11", "onos-yang-utils-generator": "mvn:org.onosproject:onos-yang-utils-generator:1.11", - "onos-yang-model":"mvn:org.onosproject:onos-yang-model:2.2.0-b3", - "onos-yang-compiler-api":"mvn:org.onosproject:onos-yang-compiler-api:2.2.0-b3", - "onos-yang-runtime":"mvn:org.onosproject:onos-yang-runtime:2.2.0-b3", - "onos-yang-serializers-json":"mvn:org.onosproject:onos-yang-serializers-json:2.2.0-b3", - "onos-yang-serializers-xml":"mvn:org.onosproject:onos-yang-serializers-xml:2.2.0-b3", - "onos-yang-serializers-utils":"mvn:org.onosproject:onos-yang-serializers-utils:2.2.0-b3", + "onos-yang-model":"mvn:org.onosproject:onos-yang-model:2.2.0-b4", + "onos-yang-compiler-api":"mvn:org.onosproject:onos-yang-compiler-api:2.2.0-b4", + "onos-yang-runtime":"mvn:org.onosproject:onos-yang-runtime:2.2.0-b4", + "onos-yang-serializers-json":"mvn:org.onosproject:onos-yang-serializers-json:2.2.0-b4", + "onos-yang-serializers-xml":"mvn:org.onosproject:onos-yang-serializers-xml:2.2.0-b4", + "onos-yang-serializers-utils":"mvn:org.onosproject:onos-yang-serializers-utils:2.2.0-b4", "org.apache.servicemix.bundles.dom4j":"mvn:org.apache.servicemix.bundles:org.apache.servicemix.bundles.dom4j:1.6.1_5", "plexus-utils": "mvn:org.codehaus.plexus:plexus-utils:3.0.24", "sshd-core": "mvn:org.apache.sshd:sshd-core:1.4.0", diff --git a/tools/dev/bin/patch-yang-libs b/tools/dev/bin/patch-yang-libs index be082d5c03..01f3935789 100755 --- a/tools/dev/bin/patch-yang-libs +++ b/tools/dev/bin/patch-yang-libs @@ -3,7 +3,7 @@ # Patches lib/BUCK file to use locally built YANG tools. # ----------------------------------------------------------------------------- -BVER=2.1 +BVER=2.2.0-b3 SVER=2.2-SNAPSHOT YANG_TOOLS_ROOT=~/onos-yang-tools diff --git a/tools/package/runtime/bin/onos-compile-yang b/tools/package/runtime/bin/onos-compile-yang new file mode 100755 index 0000000000..855167c348 --- /dev/null +++ b/tools/package/runtime/bin/onos-compile-yang @@ -0,0 +1,54 @@ +#!/bin/bash + +# +# Copyright 2015-present Open Networking Foundation +# +# 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. +# + +# ----------------------------------------------------------------------------- +# Tool to compile the specified YANG file(s) using the ONOS live compilation. +# ----------------------------------------------------------------------------- + +# If ONOS_HOME is set, respect its value. +# If ONOS_HOME is not set (e.g. in the init or service environment), +# set it based on this script's path. +ONOS_HOME=${ONOS_HOME:-$(cd $(dirname $0)/.. >/dev/null 2>&1 && pwd)} +ONOS_WEB_USER=${ONOS_WEB_USER:-onos} # ONOS WEB User defaults to 'onos' +ONOS_WEB_PASS=${ONOS_WEB_PASS:-rocks} # ONOS WEB Password defaults to 'rocks' + +. ${ONOS_HOME}/bin/_find-node + +node=$(find_node $1) +yang=$2 + +export URL=http://$node:8181/onos/yang/models +export curl="curl -sS --user $ONOS_WEB_USER:$ONOS_WEB_PASS --noproxy localhost " + +# Prints usage help +function usage { + echo "usage: onos-compile-yang " >&2 + exit 1 +} + +[ -z $node -o "$node" = "-h" -o "$node" = "--help" -o "$node" = "-?" ] && usage + +if [ -d $yang ]; then + newYang=/tmp/$(basename $yang).jar + jar cf $newYang $yang + yang=$newYang +fi + +file=$(basename $yang) +modelId="$(echo $file | sed -E 's/(.zip|.jar|.yang)$//g')" +curl $URL?modelId=$modelId -F"file=@$yang" diff --git a/web/gui/src/main/webapp/app/fw/widget/table.js b/web/gui/src/main/webapp/app/fw/widget/table.js index 1e52017058..1d8f596122 100644 --- a/web/gui/src/main/webapp/app/fw/widget/table.js +++ b/web/gui/src/main/webapp/app/fw/widget/table.js @@ -82,11 +82,11 @@ if (haveItems) { setTdWidths(tableElems.thead, width); setTdWidths(tableElems.tbody, width); - setHeight(tableElems.thead, tableElems.table.select('.table-body'), height); } else { setTdWidths(tableElems.thead, width); _width(tableElems.tbody, width + 'px'); } + setHeight(tableElems.thead, tableElems.table.select('.table-body'), height); } // sort columns state model and functions diff --git a/web/gui/src/main/webapp/app/view/app/app.html b/web/gui/src/main/webapp/app/view/app/app.html index 8f65fc4967..6eaa126ca1 100644 --- a/web/gui/src/main/webapp/app/view/app/app.html +++ b/web/gui/src/main/webapp/app/view/app/app.html @@ -15,7 +15,7 @@