From fc890dc7a243b78f33524bae64cf117c84d0a87a Mon Sep 17 00:00:00 2001 From: Vincent Behar Date: Fri, 8 Jul 2011 15:36:14 +0200 Subject: [PATCH] add support for retrieving rundeck system info --- .../java/org/rundeck/api/RundeckClient.java | 17 + .../rundeck/api/domain/RundeckSystemInfo.java | 372 ++++++++++++++++++ .../rundeck/api/parser/SystemInfoParser.java | 81 ++++ src/site/confluence/groovy.confluence | 2 + src/site/confluence/jruby.confluence | 2 + src/site/confluence/jython.confluence | 1 + .../api/parser/SystemInfoParserTest.java | 61 +++ .../org/rundeck/api/parser/system-info.xml | 1 + 8 files changed, 537 insertions(+) create mode 100644 src/main/java/org/rundeck/api/domain/RundeckSystemInfo.java create mode 100644 src/main/java/org/rundeck/api/parser/SystemInfoParser.java create mode 100644 src/test/java/org/rundeck/api/parser/SystemInfoParserTest.java create mode 100644 src/test/resources/org/rundeck/api/parser/system-info.xml diff --git a/src/main/java/org/rundeck/api/RundeckClient.java b/src/main/java/org/rundeck/api/RundeckClient.java index e1eb52a..6f7c8c5 100644 --- a/src/main/java/org/rundeck/api/RundeckClient.java +++ b/src/main/java/org/rundeck/api/RundeckClient.java @@ -32,6 +32,7 @@ import org.rundeck.api.domain.RundeckExecution; import org.rundeck.api.domain.RundeckJob; import org.rundeck.api.domain.RundeckNode; import org.rundeck.api.domain.RundeckProject; +import org.rundeck.api.domain.RundeckSystemInfo; import org.rundeck.api.domain.RundeckExecution.ExecutionStatus; import org.rundeck.api.parser.AbortParser; import org.rundeck.api.parser.ExecutionParser; @@ -40,6 +41,7 @@ import org.rundeck.api.parser.ListParser; import org.rundeck.api.parser.NodeParser; import org.rundeck.api.parser.ProjectParser; import org.rundeck.api.parser.StringParser; +import org.rundeck.api.parser.SystemInfoParser; import org.rundeck.api.util.AssertUtil; import org.rundeck.api.util.ParametersUtil; @@ -846,6 +848,21 @@ public class RundeckClient implements Serializable { new NodeParser("project/node")); } + /* + * System Info + */ + + /** + * Get system informations about the RunDeck server + * + * @return a {@link RundeckSystemInfo} instance - won't be null + * @throws RundeckApiException in case of error when calling the API + * @throws RundeckApiException if the login failed + */ + public RundeckSystemInfo getSystemInfo() throws RundeckApiException, RundeckApiLoginException { + return new ApiCall(this).get(new ApiPathBuilder("/system/info"), new SystemInfoParser("result/system")); + } + public String getUrl() { return url; } diff --git a/src/main/java/org/rundeck/api/domain/RundeckSystemInfo.java b/src/main/java/org/rundeck/api/domain/RundeckSystemInfo.java new file mode 100644 index 0000000..3089b16 --- /dev/null +++ b/src/main/java/org/rundeck/api/domain/RundeckSystemInfo.java @@ -0,0 +1,372 @@ +/* + * Copyright 2011 Vincent Behar + * + * 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.rundeck.api.domain; + +import java.io.Serializable; +import java.util.Date; +import org.apache.commons.lang.time.DurationFormatUtils; + +/** + * Represents the RunDeck system info + * + * @author Vincent Behar + */ +public class RundeckSystemInfo implements Serializable { + + private static final long serialVersionUID = 1L; + + private Date date; + + private String version; + + private String build; + + private String node; + + private String baseDir; + + private String osArch; + + private String osName; + + private String osVersion; + + private String jvmName; + + private String jvmVendor; + + private String jvmVersion; + + private Date startDate; + + private Long uptimeInMillis; + + private String cpuLoadAverage; + + private Long maxMemoryInBytes; + + private Long freeMemoryInBytes; + + private Long totalMemoryInBytes; + + private Integer runningJobs; + + private Integer activeThreads; + + /** + * @return the uptime of the server, as a human-readable string : "42 days 7 hours 3 minutes 34 seconds" + */ + public String getUptime() { + return uptimeInMillis != null ? DurationFormatUtils.formatDurationWords(uptimeInMillis, true, true) : null; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getBuild() { + return build; + } + + public void setBuild(String build) { + this.build = build; + } + + public String getNode() { + return node; + } + + public void setNode(String node) { + this.node = node; + } + + public String getBaseDir() { + return baseDir; + } + + public void setBaseDir(String baseDir) { + this.baseDir = baseDir; + } + + public String getOsArch() { + return osArch; + } + + public void setOsArch(String osArch) { + this.osArch = osArch; + } + + public String getOsName() { + return osName; + } + + public void setOsName(String osName) { + this.osName = osName; + } + + public String getOsVersion() { + return osVersion; + } + + public void setOsVersion(String osVersion) { + this.osVersion = osVersion; + } + + public String getJvmName() { + return jvmName; + } + + public void setJvmName(String jvmName) { + this.jvmName = jvmName; + } + + public String getJvmVendor() { + return jvmVendor; + } + + public void setJvmVendor(String jvmVendor) { + this.jvmVendor = jvmVendor; + } + + public String getJvmVersion() { + return jvmVersion; + } + + public void setJvmVersion(String jvmVersion) { + this.jvmVersion = jvmVersion; + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Long getUptimeInMillis() { + return uptimeInMillis; + } + + public void setUptimeInMillis(Long uptimeInMillis) { + this.uptimeInMillis = uptimeInMillis; + } + + public String getCpuLoadAverage() { + return cpuLoadAverage; + } + + public void setCpuLoadAverage(String cpuLoadAverage) { + this.cpuLoadAverage = cpuLoadAverage; + } + + public Long getMaxMemoryInBytes() { + return maxMemoryInBytes; + } + + public void setMaxMemoryInBytes(Long maxMemoryInBytes) { + this.maxMemoryInBytes = maxMemoryInBytes; + } + + public Long getFreeMemoryInBytes() { + return freeMemoryInBytes; + } + + public void setFreeMemoryInBytes(Long freeMemoryInBytes) { + this.freeMemoryInBytes = freeMemoryInBytes; + } + + public Long getTotalMemoryInBytes() { + return totalMemoryInBytes; + } + + public void setTotalMemoryInBytes(Long totalMemoryInBytes) { + this.totalMemoryInBytes = totalMemoryInBytes; + } + + public Integer getRunningJobs() { + return runningJobs; + } + + public void setRunningJobs(Integer runningJobs) { + this.runningJobs = runningJobs; + } + + public Integer getActiveThreads() { + return activeThreads; + } + + public void setActiveThreads(Integer activeThreads) { + this.activeThreads = activeThreads; + } + + @Override + public String toString() { + return "RundeckSystemInfo [activeThreads=" + activeThreads + ", baseDir=" + baseDir + ", build=" + build + + ", cpuLoadAverage=" + cpuLoadAverage + ", date=" + date + ", freeMemoryInBytes=" + freeMemoryInBytes + + ", jvmName=" + jvmName + ", jvmVendor=" + jvmVendor + ", jvmVersion=" + jvmVersion + + ", maxMemoryInBytes=" + maxMemoryInBytes + ", node=" + node + ", osArch=" + osArch + ", osName=" + + osName + ", osVersion=" + osVersion + ", runningJobs=" + runningJobs + ", startDate=" + startDate + + ", totalMemoryInBytes=" + totalMemoryInBytes + ", uptimeInMillis=" + uptimeInMillis + ", version=" + + version + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((activeThreads == null) ? 0 : activeThreads.hashCode()); + result = prime * result + ((baseDir == null) ? 0 : baseDir.hashCode()); + result = prime * result + ((build == null) ? 0 : build.hashCode()); + result = prime * result + ((cpuLoadAverage == null) ? 0 : cpuLoadAverage.hashCode()); + result = prime * result + ((date == null) ? 0 : date.hashCode()); + result = prime * result + ((freeMemoryInBytes == null) ? 0 : freeMemoryInBytes.hashCode()); + result = prime * result + ((jvmName == null) ? 0 : jvmName.hashCode()); + result = prime * result + ((jvmVendor == null) ? 0 : jvmVendor.hashCode()); + result = prime * result + ((jvmVersion == null) ? 0 : jvmVersion.hashCode()); + result = prime * result + ((maxMemoryInBytes == null) ? 0 : maxMemoryInBytes.hashCode()); + result = prime * result + ((node == null) ? 0 : node.hashCode()); + result = prime * result + ((osArch == null) ? 0 : osArch.hashCode()); + result = prime * result + ((osName == null) ? 0 : osName.hashCode()); + result = prime * result + ((osVersion == null) ? 0 : osVersion.hashCode()); + result = prime * result + ((runningJobs == null) ? 0 : runningJobs.hashCode()); + result = prime * result + ((startDate == null) ? 0 : startDate.hashCode()); + result = prime * result + ((totalMemoryInBytes == null) ? 0 : totalMemoryInBytes.hashCode()); + result = prime * result + ((uptimeInMillis == null) ? 0 : uptimeInMillis.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RundeckSystemInfo other = (RundeckSystemInfo) obj; + if (activeThreads == null) { + if (other.activeThreads != null) + return false; + } else if (!activeThreads.equals(other.activeThreads)) + return false; + if (baseDir == null) { + if (other.baseDir != null) + return false; + } else if (!baseDir.equals(other.baseDir)) + return false; + if (build == null) { + if (other.build != null) + return false; + } else if (!build.equals(other.build)) + return false; + if (cpuLoadAverage == null) { + if (other.cpuLoadAverage != null) + return false; + } else if (!cpuLoadAverage.equals(other.cpuLoadAverage)) + return false; + if (date == null) { + if (other.date != null) + return false; + } else if (!date.equals(other.date)) + return false; + if (freeMemoryInBytes == null) { + if (other.freeMemoryInBytes != null) + return false; + } else if (!freeMemoryInBytes.equals(other.freeMemoryInBytes)) + return false; + if (jvmName == null) { + if (other.jvmName != null) + return false; + } else if (!jvmName.equals(other.jvmName)) + return false; + if (jvmVendor == null) { + if (other.jvmVendor != null) + return false; + } else if (!jvmVendor.equals(other.jvmVendor)) + return false; + if (jvmVersion == null) { + if (other.jvmVersion != null) + return false; + } else if (!jvmVersion.equals(other.jvmVersion)) + return false; + if (maxMemoryInBytes == null) { + if (other.maxMemoryInBytes != null) + return false; + } else if (!maxMemoryInBytes.equals(other.maxMemoryInBytes)) + return false; + if (node == null) { + if (other.node != null) + return false; + } else if (!node.equals(other.node)) + return false; + if (osArch == null) { + if (other.osArch != null) + return false; + } else if (!osArch.equals(other.osArch)) + return false; + if (osName == null) { + if (other.osName != null) + return false; + } else if (!osName.equals(other.osName)) + return false; + if (osVersion == null) { + if (other.osVersion != null) + return false; + } else if (!osVersion.equals(other.osVersion)) + return false; + if (runningJobs == null) { + if (other.runningJobs != null) + return false; + } else if (!runningJobs.equals(other.runningJobs)) + return false; + if (startDate == null) { + if (other.startDate != null) + return false; + } else if (!startDate.equals(other.startDate)) + return false; + if (totalMemoryInBytes == null) { + if (other.totalMemoryInBytes != null) + return false; + } else if (!totalMemoryInBytes.equals(other.totalMemoryInBytes)) + return false; + if (uptimeInMillis == null) { + if (other.uptimeInMillis != null) + return false; + } else if (!uptimeInMillis.equals(other.uptimeInMillis)) + return false; + if (version == null) { + if (other.version != null) + return false; + } else if (!version.equals(other.version)) + return false; + return true; + } + +} diff --git a/src/main/java/org/rundeck/api/parser/SystemInfoParser.java b/src/main/java/org/rundeck/api/parser/SystemInfoParser.java new file mode 100644 index 0000000..9221d58 --- /dev/null +++ b/src/main/java/org/rundeck/api/parser/SystemInfoParser.java @@ -0,0 +1,81 @@ +/* + * Copyright 2011 Vincent Behar + * + * 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.rundeck.api.parser; + +import java.util.Date; +import org.apache.commons.lang.StringUtils; +import org.dom4j.Node; +import org.rundeck.api.domain.RundeckSystemInfo; + +/** + * Parser for a single {@link RundeckSystemInfo} + * + * @author Vincent Behar + */ +public class SystemInfoParser implements XmlNodeParser { + + private String xpath; + + public SystemInfoParser() { + super(); + } + + /** + * @param xpath of the systemInfo element if it is not the root node + */ + public SystemInfoParser(String xpath) { + super(); + this.xpath = xpath; + } + + @Override + public RundeckSystemInfo parseXmlNode(Node node) { + Node infoNode = xpath != null ? node.selectSingleNode(xpath) : node; + + RundeckSystemInfo info = new RundeckSystemInfo(); + + String timestamp = StringUtils.trimToNull(infoNode.valueOf("timestamp/@epoch")); + if (timestamp != null) { + info.setDate(new Date(Long.valueOf(timestamp))); + } + info.setVersion(StringUtils.trimToNull(infoNode.valueOf("rundeck/version"))); + info.setBuild(StringUtils.trimToNull(infoNode.valueOf("rundeck/build"))); + info.setNode(StringUtils.trimToNull(infoNode.valueOf("rundeck/node"))); + info.setBaseDir(StringUtils.trimToNull(infoNode.valueOf("rundeck/base"))); + info.setOsArch(StringUtils.trimToNull(infoNode.valueOf("os/arch"))); + info.setOsName(StringUtils.trimToNull(infoNode.valueOf("os/name"))); + info.setOsVersion(StringUtils.trimToNull(infoNode.valueOf("os/version"))); + info.setJvmName(StringUtils.trimToNull(infoNode.valueOf("jvm/name"))); + info.setJvmVendor(StringUtils.trimToNull(infoNode.valueOf("jvm/vendor"))); + info.setJvmVersion(StringUtils.trimToNull(infoNode.valueOf("jvm/version"))); + String startDate = StringUtils.trimToNull(infoNode.valueOf("stats/uptime/since/@epoch")); + if (startDate != null) { + info.setStartDate(new Date(Long.valueOf(startDate))); + } + info.setUptimeInMillis(Long.valueOf(infoNode.valueOf("stats/uptime/@duration"))); + info.setCpuLoadAverage(StringUtils.trimToNull(infoNode.valueOf("stats/cpu/loadAverage"))); + if (info.getCpuLoadAverage() != null) { + info.setCpuLoadAverage(info.getCpuLoadAverage() + " %"); + } + info.setMaxMemoryInBytes(Long.valueOf(infoNode.valueOf("stats/memory/max"))); + info.setFreeMemoryInBytes(Long.valueOf(infoNode.valueOf("stats/memory/free"))); + info.setTotalMemoryInBytes(Long.valueOf(infoNode.valueOf("stats/memory/total"))); + info.setRunningJobs(Integer.valueOf(infoNode.valueOf("stats/scheduler/running"))); + info.setActiveThreads(Integer.valueOf(infoNode.valueOf("stats/threads/active"))); + + return info; + } +} diff --git a/src/site/confluence/groovy.confluence b/src/site/confluence/groovy.confluence index 59c198e..2768cca 100644 --- a/src/site/confluence/groovy.confluence +++ b/src/site/confluence/groovy.confluence @@ -20,6 +20,7 @@ import org.rundeck.api.RundeckClient rundeck = new RundeckClient("http://localhost:4440", "admin", "admin") +println "RunDeck uptime : ${rundeck.systemInfo.uptime}" println "All RunDeck projects : ${rundeck.projects}" println "All RunDeck nodes : ${rundeck.nodes}" println "All RunDeck jobs : ${rundeck.jobs}" @@ -33,6 +34,7 @@ import org.rundeck.api.RundeckClient rundeck = new RundeckClient("http://localhost:4440", "admin", "admin") +println "RunDeck uptime : ${rundeck.systemInfo.uptime}" println "All RunDeck projects : ${rundeck.projects}" println "All RunDeck nodes : ${rundeck.nodes}" println "All RunDeck jobs : ${rundeck.jobs}" diff --git a/src/site/confluence/jruby.confluence b/src/site/confluence/jruby.confluence index 7dbbbc2..7fe128c 100644 --- a/src/site/confluence/jruby.confluence +++ b/src/site/confluence/jruby.confluence @@ -16,6 +16,7 @@ import org.rundeck.api.RundeckClient rundeck = RundeckClient.new("http://localhost:4440", "admin", "admin") +puts "RunDeck uptime : #{rundeck.systemInfo.uptime}" puts "All RunDeck projects : #{rundeck.projects}" puts "All RunDeck nodes : #{rundeck.nodes}" puts "All RunDeck jobs : #{rundeck.jobs}" @@ -29,6 +30,7 @@ import org.rundeck.api.RundeckClient rundeck = RundeckClient.new("http://localhost:4440", "admin", "admin") +puts "RunDeck uptime : #{rundeck.systemInfo.uptime}" puts "All RunDeck projects : #{rundeck.projects}" puts "All RunDeck nodes : #{rundeck.nodes}" puts "All RunDeck jobs : #{rundeck.jobs}" diff --git a/src/site/confluence/jython.confluence b/src/site/confluence/jython.confluence index 2c21bfb..0175837 100644 --- a/src/site/confluence/jython.confluence +++ b/src/site/confluence/jython.confluence @@ -14,6 +14,7 @@ from org.rundeck.api import RundeckClient rundeck = RundeckClient("http://localhost:4440", "admin", "admin") +print("RunDeck uptime : %s" % rundeck.systemInfo.uptime) print("All RunDeck projects : %s" % rundeck.projects) print("All RunDeck nodes : %s" % rundeck.nodes) print("All RunDeck jobs : %s" % rundeck.jobs) diff --git a/src/test/java/org/rundeck/api/parser/SystemInfoParserTest.java b/src/test/java/org/rundeck/api/parser/SystemInfoParserTest.java new file mode 100644 index 0000000..19b997b --- /dev/null +++ b/src/test/java/org/rundeck/api/parser/SystemInfoParserTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011 Vincent Behar + * + * 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.rundeck.api.parser; + +import java.io.InputStream; +import java.util.Date; +import org.dom4j.Document; +import org.junit.Assert; +import org.junit.Test; +import org.rundeck.api.domain.RundeckSystemInfo; + +/** + * Test the {@link SystemInfoParser} + * + * @author Vincent Behar + */ +public class SystemInfoParserTest { + + @Test + public void parseProject() throws Exception { + InputStream input = getClass().getResourceAsStream("system-info.xml"); + Document document = ParserHelper.loadDocument(input); + + RundeckSystemInfo info = new SystemInfoParser("result/system").parseXmlNode(document); + + Assert.assertEquals(new Date(1310051857605L), info.getDate()); + Assert.assertEquals("1.2.1", info.getVersion()); + Assert.assertEquals("1.2.1-1", info.getBuild()); + Assert.assertEquals("strongbad", info.getNode()); + Assert.assertEquals("/opt/rundeck/rundeck-1.2.1", info.getBaseDir()); + Assert.assertEquals("i386", info.getOsArch()); + Assert.assertEquals("Linux", info.getOsName()); + Assert.assertEquals("2.6.35-30-generic-pae", info.getOsVersion()); + Assert.assertEquals("Java HotSpot(TM) Server VM", info.getJvmName()); + Assert.assertEquals("Sun Microsystems Inc.", info.getJvmVendor()); + Assert.assertEquals("19.1-b02", info.getJvmVersion()); + Assert.assertEquals(new Date(1310032513574L), info.getStartDate()); + Assert.assertEquals(new Long(19344031), info.getUptimeInMillis()); + Assert.assertEquals("5 hours 22 minutes 24 seconds", info.getUptime()); + Assert.assertEquals("0.1 %", info.getCpuLoadAverage()); + Assert.assertEquals(new Long(954466304), info.getMaxMemoryInBytes()); + Assert.assertEquals(new Long(159576592), info.getFreeMemoryInBytes()); + Assert.assertEquals(new Long(271384576), info.getTotalMemoryInBytes()); + Assert.assertEquals(new Integer(0), info.getRunningJobs()); + Assert.assertEquals(new Integer(25), info.getActiveThreads()); + } + +} diff --git a/src/test/resources/org/rundeck/api/parser/system-info.xml b/src/test/resources/org/rundeck/api/parser/system-info.xml new file mode 100644 index 0000000..36d9b5e --- /dev/null +++ b/src/test/resources/org/rundeck/api/parser/system-info.xml @@ -0,0 +1 @@ +System Stats for RunDeck 1.2.1 on node strongbad2011-07-07T15:17:37Z1.2.11.2.1-1strongbad/opt/rundeck/rundeck-1.2.1i386Linux2.6.35-30-generic-paeJava HotSpot(TM) Server VMSun Microsystems Inc.19.1-b022011-07-07T09:55:13Z0.12954466304159576592271384576025 \ No newline at end of file