diff --git a/apps/nodemetrics/BUCK b/apps/nodemetrics/BUCK new file mode 100644 index 0000000000..65c845e73e --- /dev/null +++ b/apps/nodemetrics/BUCK @@ -0,0 +1,17 @@ +BUNDLES = [ + '//apps/nodemetrics/api:onos-apps-nodemetrics-api', + '//apps/nodemetrics/mgr:onos-apps-nodemetrics-mgr', +] + +onos_app( + app_name = 'org.onosproject.nodemetrics', + title = 'Controller Monitor Application', + description = '1.Nodemetrics Application uses, sigar library to fetch Controller information.'+ + '2. The Sigar library uses Native libraries and currently It supports Windows, Linux and MacOs platform.'+ + '3. The Native libraries like .so, .dll and .dylib are packed as jar along with sigar libs.'+ + '4. If the Native libraries are corrupted because of any reason,'+ + 'so, the controller is vulnerable to crash of the entire JVM', + category = 'Utility', + url = 'http://samsung.com', + included_bundles = BUNDLES +) \ No newline at end of file diff --git a/apps/nodemetrics/api/BUCK b/apps/nodemetrics/api/BUCK new file mode 100644 index 0000000000..42b99a6aca --- /dev/null +++ b/apps/nodemetrics/api/BUCK @@ -0,0 +1,9 @@ +COMPILE_DEPS = [ + '//lib:CORE_DEPS', + '//lib:sigar', + +] + +osgi_jar_with_tests( + deps = COMPILE_DEPS, +) \ No newline at end of file diff --git a/apps/nodemetrics/api/pom.xml b/apps/nodemetrics/api/pom.xml new file mode 100644 index 0000000000..16dfd043a1 --- /dev/null +++ b/apps/nodemetrics/api/pom.xml @@ -0,0 +1,110 @@ + + + + 4.0.0 + + + org.onosproject + onos-apps-nodemetrics + 1.14.0-SNAPSHOT + + + + onos-apps-nodemetrics-api + bundle + + ONOS Nodemetrics API + http://onosproject.org + + + UTF-8 + ${project.version} + + + + + org.onosproject + onos-api + test + tests + + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.apache.felix + maven-scr-plugin + + + generate-scr-srcdescriptor + + scr + + + + + + bundle + war + + + + + + org.onosproject + onos-maven-plugin + + + cfg + generate-resources + + cfg + + + + swagger + generate-sources + + swagger + + + + app + package + + app + + + + + + + + diff --git a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeCpu.java b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeCpu.java new file mode 100644 index 0000000000..87a79c0edb --- /dev/null +++ b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeCpu.java @@ -0,0 +1,112 @@ +/* + * 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.nodemetrics; + +import com.google.common.base.MoreObjects; +import org.onosproject.cluster.NodeId; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents CPU usage info of Cluster controllers. + */ +public final class NodeCpu { + private final NodeId node; + private final double usage; + + private NodeCpu(final NodeId node, final Double usage) { + this.node = node; + this.usage = usage; + } + + /** + * Overall usage of CPU includes combined usage of + * (user,sys,nice,idle,wait,irq,softIrq and stolen) etc. + * @return usage is overall usage of CPU for the Specific Node. + */ + public double usage() { + return usage; + } + + @Override + public String toString() { + + return MoreObjects.toStringHelper(this) + .add("node", this.node) + .add("usage", String.format("%.2f%s", this.usage, "%")) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(node, usage); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final NodeCpu other = (NodeCpu) obj; + return Objects.equals(this.node, other.node) + && Objects.equals(this.usage, other.usage); + } + + /** + * Builder for the DefaultNodeCpu object. + */ + public static final class Builder { + /** + * Builds the DefaultNodeCpu. + **/ + private NodeId node; + private Double usage; + + /** + * Sets the DefaultNodeCpu usage from Library. + * + * @param usage of CPU + * @return self for chaining + */ + public Builder usage(final Double usage) { + this.usage = usage; + return this; + } + + /** + * Sets the new DefaultNodeCpu controller node id. + * + * @param node the nodeId + * @return self for chaining + */ + public Builder withNode(final NodeId node) { + this.node = node; + return this; + } + + public NodeCpu build() { + checkNotNull(node, "Must specify an node id"); + checkNotNull(usage, "Must specify a usage"); + return new NodeCpu(node, usage); + } + } + +} diff --git a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeDiskUsage.java b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeDiskUsage.java new file mode 100644 index 0000000000..280c2300bc --- /dev/null +++ b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeDiskUsage.java @@ -0,0 +1,207 @@ +/* + * 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.nodemetrics; + +import com.google.common.base.MoreObjects; +import org.onosproject.cluster.NodeId; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents Disk usage of Cluster controllers. + */ +public final class NodeDiskUsage { + + private final NodeId node; + + private final long free; + + private final long used; + + private final long total; + + private final Units units; + + private final double usage; + + private static final double PERCENTAGE_MULTIPLIER = 100.0; + + private NodeDiskUsage(final NodeId node, final Long free, + final Long used, final Long total, final Units units, + final Double usage) { + this.node = node; + this.free = free; + this.used = used; + this.total = total; + this.units = units; + this.usage = usage; + } + + /** + * @return free disk space available available for the specific nodeId. + */ + public long free() { + return free; + } + + /** + * @return used disk space used for the specific nodeId. + */ + public long used() { + return used; + } + + /** + * @return total disk space for the specific nodeId.. + */ + public long total() { + return total; + } + + /** + * @return units in Kbs /Mbs/ Gbs. + */ + public Units units() { + return units; + } + + /** + * Percentage of Disk usage is calculated from Used, + * Available and Total Disk available in Specific Node. + * @return usage overall usage of Disk space for the specific nodeId. + */ + public double usage() { + return usage; + } + + @Override + public int hashCode() { + return Objects.hash(node, free, used, total, units, usage); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("node", this.node) + .add("free", this.free) + .add("used", this.used) + .add("total", this.total) + .add("units", this.units) + .add("usage", this.usage + "%") + .toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + NodeDiskUsage other = (NodeDiskUsage) obj; + return Objects.equals(this.node, other.node) + && Objects.equals(this.free, other.free) + && Objects.equals(this.used, other.used) + && Objects.equals(this.total, other.total) + && Objects.equals(this.units, other.units) + && Objects.equals(this.usage, other.usage); + } + + /** + * Builder for the NodeDiskusage object. + */ + public static final class Builder { + /** + * Builds the NodeDiskusage. + **/ + private NodeId node; + private Units unit; + private Long free; + private Long used; + private Long total; + + /** + * Sets the new NodeDiskusage controller nodeid. + * + * @param node the nodeId + * @return self for chaining + */ + public Builder withNode(final NodeId node) { + this.node = node; + return this; + } + + /** + * Sets the new NodeDiskusage Disk size units(bytes, Kbs, Mbs, + * Gbs). + * + * @param unit the units + * @return self for chaining + */ + public Builder withUnit(final Units unit) { + this.unit = unit; + return this; + } + + /** + * Sets the new NodeDiskusage controller free space. + * + * @param free the free space + * @return self for chaining + */ + public Builder free(final Long free) { + this.free = free; + return this; + } + + /** + * Sets the new NodeDiskusage controller used space. + * + * @param used the used space + * @return self for chaining + */ + public Builder used(final Long used) { + this.used = used; + return this; + } + + /** + * Sets the new NodeDiskusage controller total disk. + * + * @param total the total disk space + * @return self for chaining + */ + public Builder total(final Long total) { + this.total = total; + return this; + } + + public NodeDiskUsage build() { + checkNotNull(node, "Must specify an node id"); + checkNotNull(unit, "Must specify a unit"); + checkNotNull(used, "Must specify a used Diskspace"); + checkNotNull(free, "Must specify a free Diskspace"); + checkNotNull(total, "Must specify a total Diskspace"); + double usage = used * PERCENTAGE_MULTIPLIER / total; + return new NodeDiskUsage(node, free, used, total, unit, usage); + } + + } + +} \ No newline at end of file diff --git a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMemory.java b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMemory.java new file mode 100644 index 0000000000..399bc9076a --- /dev/null +++ b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMemory.java @@ -0,0 +1,206 @@ +/* + * 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.nodemetrics; + +import com.google.common.base.MoreObjects; +import org.onosproject.cluster.NodeId; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents Memory usage of Cluster controllers. + */ +public final class NodeMemory { + + private final NodeId node; + + private final Units units; + + private final long free; + + private final long used; + + private final long total; + + private final double usage; + + private static final double PERCENTAGE_MULTIPLIER = 100.0; + + private NodeMemory(final NodeId node, final Units units, + final Long free, final Long used, final Long total, + final Double usage) { + this.node = node; + this.units = units; + this.free = free; + this.used = used; + this.total = total; + this.usage = usage; + } + + /** + * @return free memory available for the specific nodeId. + */ + public long free() { + return free; + } + + /** + * @return used memory for the specific nodeId.. + */ + public long used() { + return used; + } + + /** + * @return total memory for the specific nodeId.. + */ + public long total() { + return total; + } + + /** + * @return memory in Kbs / Mbs etc. + */ + public Units units() { + return units; + } + + /** + * Percentage of Memory usage is calculated from Used, Available and Total Memory. + * @return usage overall usage of memory in percentage for the specific node. + */ + public double usage() { + return usage; + } + + @Override + public int hashCode() { + return Objects.hash(node, free, used, total, units, usage); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("node", this.node) + .add("free", this.free) + .add("used", this.used) + .add("total", this.total) + .add("units", this.units.toString()) + .add("usage", this.usage + "%") + .toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + NodeMemory other = (NodeMemory) obj; + return Objects.equals(this.node, other.node) + && Objects.equals(this.free, other.free) + && Objects.equals(this.used, other.used) + && Objects.equals(this.total, other.total) + && Objects.equals(this.units, other.units) + && Objects.equals(this.usage, other.usage); + } + + /** + * Builder for the DefaultNodeMemory object. + */ + public static final class Builder { + /** + * Builds the DefaultNodeMemory. + **/ + private NodeId node; + private Units unit; + private Long free; + private Long used; + private Long total; + + /** + * Sets the new DefaultNodeMemory controller nodeId. + * + * @param node nodeId + * @return self for chaining + */ + public Builder withNode(final NodeId node) { + this.node = node; + return this; + } + + /** + * Sets the new DefaultNodeMemory Disk size units(bytes, Kbs, Mbs, Gbs). + * + * @param unit units + * @return self for chaining + */ + public Builder withUnit(final Units unit) { + this.unit = unit; + return this; + } + + /** + * Sets the new DefaultNodeMemory controller free space. + * + * @param free free space + * @return self for chaining + */ + public Builder free(final Long free) { + this.free = free; + return this; + } + + /** + * Sets the new DefaultNodeMemory controller used space. + * + * @param used used space + * @return self for chaining + */ + public Builder used(final Long used) { + this.used = used; + return this; + } + + /** + * Sets the new DefaultNodeMemory controller total disk. + * + * @param total the total disk space + * @return self for chaining + */ + public Builder total(final Long total) { + this.total = total; + return this; + } + + public NodeMemory build() { + checkNotNull(node, "Must specify an node id"); + checkNotNull(unit, "Must specify a unit"); + checkNotNull(used, "Must specify a used Diskspace"); + checkNotNull(free, "Must specify a free Diskspace"); + checkNotNull(total, "Must specify a total Diskspace"); + double usage = used * PERCENTAGE_MULTIPLIER / total; + return new NodeMemory(node, unit, free, used, total, usage); + } + + } + +} \ No newline at end of file diff --git a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMetricsService.java b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMetricsService.java new file mode 100644 index 0000000000..1228fb0e7e --- /dev/null +++ b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMetricsService.java @@ -0,0 +1,67 @@ +/* + * 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.nodemetrics; + +import org.onosproject.cluster.NodeId; + +import java.util.Map; + +/** + * Nodemetrics Application is to fetch Controller Resource metrics. + * The Control Resource metrics includes Memory, + * CPU usage and Disk usage of All the cluster nodes. + */ +public interface NodeMetricsService { + /** + * Returns may memory information of all Cluster nodes. + * @return map + */ + Map memory(); + + /** + * Returns may disk information of all Cluster nodes. + * @return map + */ + Map disk(); + + /** + * Returns may CPU information of all Cluster nodes. + * @return map object, NodeId as key and NodeCpu information as value. + */ + Map cpu(); + + /** + * Get the memory information of Specific Cluster node. + * @param nodeid to get Memory information of that respective cluster node. + * @return Nodememory object. + */ + NodeMemory memory(NodeId nodeid); + + /** + * Get the disk information of Specific Cluster node. + * @param nodeid to get disk information of that respective cluster node. + * @return NodeDiskUsage object. + */ + NodeDiskUsage disk(NodeId nodeid); + + /** + * Get the CPU information of Specific Cluster node. + * @param nodeid to get CPU information of that respective cluster node. + * @return NodeCpu object. + */ + NodeCpu cpu(NodeId nodeid); +} diff --git a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/Units.java b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/Units.java new file mode 100644 index 0000000000..30e85a9621 --- /dev/null +++ b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/Units.java @@ -0,0 +1,38 @@ +/* + * 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.nodemetrics; + +public enum Units { + /** + * Units for Memory and Disk. + */ + BYTES("bytes"), KBYTES("Kbs"), MBYTES("Mbs"), GBYTES("Gbs"); + + private final String units; + + Units(String units) { + this.units = units; + } + + /** + * Returns units for Memory and Diskusage. + * @return units for Memory and Diskusage + */ + public String units() { + return units; + } +} diff --git a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/package-info.java b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/package-info.java new file mode 100644 index 0000000000..1f4d7ed325 --- /dev/null +++ b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/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. + */ + +/** + * Module to fetch Node Metrics. + */ +package org.onosproject.nodemetrics; \ No newline at end of file diff --git a/apps/nodemetrics/mgr/BUCK b/apps/nodemetrics/mgr/BUCK new file mode 100644 index 0000000000..35d3657f4a --- /dev/null +++ b/apps/nodemetrics/mgr/BUCK @@ -0,0 +1,13 @@ +COMPILE_DEPS = [ + '//lib:CORE_DEPS', + '//lib:sigar', + '//lib:org.apache.karaf.shell.console', + '//apps/nodemetrics/api:onos-apps-nodemetrics-api', + '//core/store/serializers:onos-core-serializers', + '//cli:onos-cli', + '//lib:KRYO', +] + +osgi_jar_with_tests( + deps = COMPILE_DEPS, +) \ No newline at end of file diff --git a/apps/nodemetrics/mgr/pom.xml b/apps/nodemetrics/mgr/pom.xml new file mode 100644 index 0000000000..b9ea3b7d8a --- /dev/null +++ b/apps/nodemetrics/mgr/pom.xml @@ -0,0 +1,147 @@ + + + + 4.0.0 + + + org.onosproject + onos-apps-nodemetrics + 1.14.0-SNAPSHOT + + + + onos-apps-nodemetrics-mgr + bundle + + ONOS nodemetrics API + http://onosproject.org + + + UTF-8 + ${project.version} + + + + + + org.onosproject + onos-models-openconfig + ${project.version} + + + + + + + org.onosproject + onos-api + test + tests + + + org.onosproject + onos-apps-nodemetrics-api + 1.14.0-SNAPSHOT + + + org.knowhowlab.osgi + sigar + 1.6.5_01 + + + org.onosproject + onos-core-serializers + 1.14.0-SNAPSHOT + + + biz.aQute.bnd + biz.aQute.bndlib + 3.5.0 + + + org.apache.karaf.shell + org.apache.karaf.shell.console + 3.0.8 + + + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.apache.felix + maven-scr-plugin + + + generate-scr-srcdescriptor + + scr + + + + + + bundle + war + + + + + + org.onosproject + onos-maven-plugin + + + cfg + generate-resources + + cfg + + + + swagger + generate-sources + + swagger + + + + app + package + + app + + + + + + + + diff --git a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeCpuUsageCommand.java b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeCpuUsageCommand.java new file mode 100644 index 0000000000..a12279125d --- /dev/null +++ b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeCpuUsageCommand.java @@ -0,0 +1,61 @@ +/* + * 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.nodemetrics.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cluster.NodeId; +import org.onosproject.nodemetrics.NodeCpu; +import org.onosproject.nodemetrics.NodeMetricsService; + +import java.util.Collection; +import java.util.Objects; + +/** + * Lists cpu usage across nodes. + */ +@Command(scope = "onos", name = "node-cpu", + description = "Lists all node cpu utilization") +public class ShowNodeCpuUsageCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "nodeId", description = "Node identity", + required = false, multiValued = false) + String nodeId = null; + private NodeMetricsService nodeService = AbstractShellCommand + .get(NodeMetricsService.class); + + @Override + protected void execute() { + if (nodeId != null) { + NodeCpu cpu = nodeService.cpu(NodeId.nodeId(nodeId)); + if (Objects.nonNull(cpu)) { + print("CPU usage : %s ", cpu); + } else { + print("Node %s doesn't exists", nodeId); + } + } else { + Collection cpu = nodeService.cpu().values(); + printCpuUsage(cpu); + } + } + + private void printCpuUsage(Collection cpuList) { + cpuList.forEach(cpu -> print("%s", cpu)); + } +} + diff --git a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeDiskUsageCommand.java b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeDiskUsageCommand.java new file mode 100644 index 0000000000..8dc0f09372 --- /dev/null +++ b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeDiskUsageCommand.java @@ -0,0 +1,61 @@ +/* + * 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.nodemetrics.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cluster.NodeId; +import org.onosproject.nodemetrics.NodeDiskUsage; +import org.onosproject.nodemetrics.NodeMetricsService; + +import java.util.Collection; +import java.util.Objects; + +/** + * Lists disk usage across nodes. + */ +@Command(scope = "onos", name = "node-disk", + description = "Lists all node disk utilization") +public class ShowNodeDiskUsageCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "nodeId", description = "Node identity", + required = false, multiValued = false) + String nodeId = null; + private NodeMetricsService nodeService = AbstractShellCommand + .get(NodeMetricsService.class); + + @Override + protected void execute() { + if (nodeId != null) { + NodeDiskUsage disk = nodeService.disk(NodeId.nodeId(nodeId)); + if (Objects.nonNull(disk)) { + print("Disk usage : %s", disk); + } else { + print("Node %s doesn't exists", nodeId); + } + + } else { + Collection disk = nodeService.disk().values(); + printDiskUsage(disk); + } + } + + private void printDiskUsage(Collection diskList) { + diskList.forEach(disk -> print("%s", disk)); + } +} diff --git a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeMemoryCommand.java b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeMemoryCommand.java new file mode 100644 index 0000000000..3c6ec5bee6 --- /dev/null +++ b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeMemoryCommand.java @@ -0,0 +1,60 @@ +/* + * 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.nodemetrics.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cluster.NodeId; +import org.onosproject.nodemetrics.NodeMemory; +import org.onosproject.nodemetrics.NodeMetricsService; + +import java.util.Collection; +import java.util.Objects; + +/** + * Lists memory usage across nodes. + */ +@Command(scope = "onos", name = "node-memory", + description = "Lists all node memory utilization") +public class ShowNodeMemoryCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "nodeId", description = "Node identity", + required = false, multiValued = false) + String nodeId = null; + private NodeMetricsService nodeService = AbstractShellCommand + .get(NodeMetricsService.class); + + @Override + protected void execute() { + if (nodeId != null) { + NodeMemory memory = nodeService.memory(NodeId.nodeId(nodeId)); + if (Objects.nonNull(memory)) { + print("Memory usage : %s", memory.toString()); + } else { + print("Node %s doesn't exists"); + } + } else { + Collection memory = nodeService.memory().values(); + printMemory(memory); + } + } + + private void printMemory(Collection memoryList) { + memoryList.forEach(memory -> print("%s", memory)); + } +} diff --git a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/package-info.java b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/package-info.java new file mode 100644 index 0000000000..d4594821cf --- /dev/null +++ b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/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. + */ + +/** + * Module to fetch Node Metrics using CLI. + */ +package org.onosproject.nodemetrics.cli; \ No newline at end of file diff --git a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/impl/NodeMetricsManager.java b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/impl/NodeMetricsManager.java new file mode 100644 index 0000000000..c91f9d8bfe --- /dev/null +++ b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/impl/NodeMetricsManager.java @@ -0,0 +1,196 @@ +/* + * 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.nodemetrics.impl; + +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.hyperic.sigar.CpuPerc; +import org.hyperic.sigar.FileSystemUsage; +import org.hyperic.sigar.Mem; +import org.hyperic.sigar.Sigar; +import org.hyperic.sigar.SigarException; +import org.onlab.util.KryoNamespace; +import org.onlab.util.Tools; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.NodeId; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.nodemetrics.NodeCpu; +import org.onosproject.nodemetrics.NodeDiskUsage; +import org.onosproject.nodemetrics.NodeMemory; +import org.onosproject.nodemetrics.NodeMetricsService; +import org.onosproject.nodemetrics.Units; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.EventuallyConsistentMap; +import org.onosproject.store.service.LogicalClockService; +import org.onosproject.store.service.StorageService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Service +@Component(immediate = true) +public class NodeMetricsManager implements NodeMetricsService { + private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 15; + private static final String SLASH = "/"; + private static final Double PERCENTAGE_MULTIPLIER = 100.0; + private final Logger log = LoggerFactory + .getLogger(this.getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LogicalClockService clockService; + + private ScheduledExecutorService metricsExecutor; + private ScheduledFuture scheduledTask; + + private ApplicationId appId; + private NodeId localNodeId; + + private EventuallyConsistentMap memoryStore; + private EventuallyConsistentMap diskStore; + private EventuallyConsistentMap cpuStore; + + private Sigar sigar; + + @Activate + public void activate() { + appId = coreService + .registerApplication("org.onosproject.nodemetrics"); + metricsExecutor = Executors.newSingleThreadScheduledExecutor( + Tools.groupedThreads("nodemetrics/pollingStatics", + "statistics-executor-%d", log)); + + localNodeId = clusterService.getLocalNode().id(); + KryoNamespace.Builder serializer = KryoNamespace.newBuilder() + .register(KryoNamespaces.API) + .register(NodeMemory.class) + .register(NodeDiskUsage.class) + .register(NodeCpu.class) + .register(Units.class); + memoryStore = storageService.eventuallyConsistentMapBuilder() + .withSerializer(serializer) + .withTimestampProvider((nodeId, memory) -> clockService.getTimestamp()) + .withName("nodemetrics-memory") + .build(); + + diskStore = storageService.eventuallyConsistentMapBuilder() + .withSerializer(serializer) + .withTimestampProvider((nodeId, disk) -> clockService.getTimestamp()) + .withName("nodemetrics-disk") + .build(); + + cpuStore = storageService.eventuallyConsistentMapBuilder() + .withSerializer(serializer) + .withTimestampProvider((nodeId, cpu) -> clockService.getTimestamp()) + .withName("nodemetrics-cpu") + .build(); + + scheduledTask = schedulePolling(); + sigar = new Sigar(); + pollMetrics(); + } + + @Deactivate + public void deactivate() { + scheduledTask.cancel(true); + metricsExecutor.shutdown(); + sigar.close(); + } + + @Override + public Map memory() { + return this.ecToMap(memoryStore); + } + + @Override + public Map disk() { + return this.ecToMap(diskStore); + } + + @Override + public Map cpu() { + return this.ecToMap(cpuStore); + } + + @Override + public NodeMemory memory(NodeId nodeid) { + return memoryStore.get(nodeid); + } + + @Override + public NodeDiskUsage disk(NodeId nodeid) { + return diskStore.get(nodeid); + } + + @Override + public NodeCpu cpu(NodeId nodeid) { + return cpuStore.get(nodeid); + } + + private ScheduledFuture schedulePolling() { + return metricsExecutor.scheduleAtFixedRate(this::pollMetrics, + DEFAULT_POLL_FREQUENCY_SECONDS / 4, + DEFAULT_POLL_FREQUENCY_SECONDS, TimeUnit.SECONDS); + } + + private Map ecToMap(EventuallyConsistentMap ecMap) { + return ecMap.entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + private void pollMetrics() { + try { + CpuPerc cpu = sigar.getCpuPerc(); + Mem mem = sigar.getMem(); + FileSystemUsage disk = sigar.getFileSystemUsage(SLASH); + + NodeMemory memoryNode = new NodeMemory.Builder().free(mem.getFree()) + .used(mem.getUsed()).total(mem.getTotal()).withUnit(Units.BYTES) + .withNode(localNodeId).build(); + NodeCpu cpuNode = new NodeCpu.Builder().withNode(localNodeId) + .usage(cpu.getCombined() * PERCENTAGE_MULTIPLIER).build(); + NodeDiskUsage diskNode = new NodeDiskUsage.Builder().withNode(localNodeId) + .free(disk.getFree()).used(disk.getUsed()).withUnit(Units.KBYTES) + .total(disk.getTotal()).build(); + diskStore.put(localNodeId, diskNode); + memoryStore.put(localNodeId, memoryNode); + cpuStore.put(localNodeId, cpuNode); + + } catch (SigarException e) { + log.error("Exception occurred ", e); + } + + } +} diff --git a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/impl/package-info.java b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/impl/package-info.java new file mode 100644 index 0000000000..46ba85be56 --- /dev/null +++ b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/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. + */ + +/** + * Module to fetch Node Metrics and its Implementation. + */ +package org.onosproject.nodemetrics.impl; \ No newline at end of file diff --git a/apps/nodemetrics/mgr/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/nodemetrics/mgr/src/main/resources/OSGI-INF/blueprint/shell-config.xml new file mode 100644 index 0000000000..8bb1d693be --- /dev/null +++ b/apps/nodemetrics/mgr/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/nodemetrics/pom.xml b/apps/nodemetrics/pom.xml new file mode 100644 index 0000000000..ca8a7fef89 --- /dev/null +++ b/apps/nodemetrics/pom.xml @@ -0,0 +1,37 @@ + + + + 4.0.0 + + + org.onosproject + onos-apps + 1.14.0-SNAPSHOT + + + onos-apps-nodemetrics + pom + + ONOS nodemetrics application + + + api + mgr + + + diff --git a/apps/pom.xml b/apps/pom.xml index eb602353cb..dfdcf92982 100644 --- a/apps/pom.xml +++ b/apps/pom.xml @@ -105,6 +105,7 @@ layout imr t3 + nodemetrics diff --git a/features/BUCK b/features/BUCK index 2dd925c640..03ee6cfd56 100644 --- a/features/BUCK +++ b/features/BUCK @@ -42,6 +42,7 @@ osgi_feature ( '//lib:commons-jxpath', # FIXME: move xpath lib dependency to the right place '//lib:commons-beanutils', # jxpath dependency '//lib:jdom', # jxpath dependency + '//lib:sigar', ] ) diff --git a/lib/BUCK b/lib/BUCK index 1b7775ed55..155d066e5f 100644 --- a/lib/BUCK +++ b/lib/BUCK @@ -1,4 +1,5 @@ # ***** This file was auto-generated at Wed, 16 May 2018 01:37:51 GMT. Do not edit this file manually. ***** +# ***** This file was auto-generated at Wed, 9 May 2018 07:17:00 GMT. Do not edit this file manually. ***** # ***** Use onos-lib-gen ***** pass_thru_pom( @@ -1670,3 +1671,12 @@ remote_jar ( visibility = [ 'PUBLIC' ], ) +remote_jar ( + name = 'sigar', + out = 'sigar-1.6.5_01.jar', + url = 'mvn:org.knowhowlab.osgi:sigar:jar:1.6.5_01', + sha1 = '58eb4af0dc4a1d331cd7620767216494e2984dea', + maven_coords = 'org.knowhowlab.osgi:sigar:1.6.5_01', + visibility = [ 'PUBLIC' ], +) + diff --git a/lib/deps.json b/lib/deps.json index 690cb38308..701aed1f49 100644 --- a/lib/deps.json +++ b/lib/deps.json @@ -286,6 +286,7 @@ "aalto-xml": "mvn:com.fasterxml:aalto-xml:1.0.0", "stax2-api": "mvn:org.codehaus.woodstox:stax2-api:4.0.0", "concurrent-hashmap": "mvn:com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.0", - "gnu-idn": "mvn:org.gnu.inet:libidn:1.15" + "gnu-idn": "mvn:org.gnu.inet:libidn:1.15", + "sigar":"mvn:org.knowhowlab.osgi:sigar:1.6.5_01" } } diff --git a/modules.defs b/modules.defs index a915148cf1..be913b6da4 100644 --- a/modules.defs +++ b/modules.defs @@ -251,6 +251,8 @@ ONOS_APPS = [ '//apps/mcast:onos-apps-mcast-oar', '//apps/layout:onos-apps-layout-oar', '//apps/imr:onos-apps-imr-oar', + # nodemetrics application + '//apps/nodemetrics:onos-apps-nodemetrics-oar', ] PROTOCOL_APPS = [