[PATCH matahari] Introduces a multiplexer for taking requests and mapping them to APIs.
by Darryl L. Pierce
The Multiplexer lets Matahari register APIs and then call them by that
registered name. APIs are function pointers in the form of:
const char* function(const char *);
where the API takes as input a descriptor containing any arguments, and
returns an array containing the response or result.
Also adds a testing directory and unit tests to validate the
Multiplexer.
The new directory, src/tests, has its own standalone makefile that
builds the tests.
Signed-off-by: Darryl L. Pierce <dpierce(a)redhat.com>
---
configure.ac | 3 +-
src/Makefile.am | 6 ++-
src/tests/.gitignore | 1 +
src/tests/Makefile.am | 13 +++++
src/tests/testmultiplexer.cpp | 109 +++++++++++++++++++++++++++++++++++++++++
src/tests/testmultiplexer.h | 46 +++++++++++++++++
src/virtio/multiplexer.cpp | 62 +++++++++++++++++++++++
src/virtio/multiplexer.h | 48 ++++++++++++++++++
8 files changed, 285 insertions(+), 3 deletions(-)
create mode 100644 src/tests/.gitignore
create mode 100644 src/tests/Makefile.am
create mode 100644 src/tests/testmultiplexer.cpp
create mode 100644 src/tests/testmultiplexer.h
create mode 100644 src/virtio/multiplexer.cpp
create mode 100644 src/virtio/multiplexer.h
diff --git a/configure.ac b/configure.ac
index 42d319b..3481c09 100644
--- a/configure.ac
+++ b/configure.ac
@@ -21,6 +21,7 @@ AC_HEADER_STDBOOL
AC_TYPE_UINT32_T
# Checks for libraries.
+PKG_CHECK_MODULES(CPPUNIT, cppunit >= 1.12.1)
PKG_CHECK_MODULES(LIBVIRT, libvirt >= 0.6.2)
PKG_CHECK_MODULES(PCRE, libpcre >= 7.8)
PKG_CHECK_MODULES(UDEV, libudev >= 145)
@@ -28,4 +29,4 @@ PKG_CHECK_MODULES(UDEV, libudev >= 145)
# Checks for library functions.
AC_CHECK_FUNCS([gethostname inet_ntoa socket])
-AC_OUTPUT(Makefile src/Makefile)
+AC_OUTPUT(Makefile src/Makefile src/tests/Makefile)
diff --git a/src/Makefile.am b/src/Makefile.am
index 498ee72..7b5245a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,7 +32,9 @@ matahari_SOURCES = \
qmf/hostagent.cpp \
qmf/hostagent.h \
qmf/processorsagent.cpp \
- qmf/processorsagent.h
+ qmf/processorsagent.h \
+ virtio/multiplexer.cpp \
+ virtio/multiplexer.h
$(generated_file_list): $(generated_file_list)
@@ -44,6 +46,6 @@ CLEANFILES = $(generated_file_list) $(first)
matahari_CPPFLAGS = -fno-strict-aliasing
matahari_LDFLAGS = -L/usr/local/lib
-matahari_LDADD = -lqmf $(LIBVIRT_LIBS) $(PCRE_LIBS) $(UDEV_LIBS)
+matahari_LDADD = -lqmf -lqpidclient -lqpidcommon $(LIBVIRT_LIBS) $(PCRE_LIBS) $(UDEV_LIBS)
dist_pkgdata_DATA = schema.xml
diff --git a/src/tests/.gitignore b/src/tests/.gitignore
new file mode 100644
index 0000000..06042ff
--- /dev/null
+++ b/src/tests/.gitignore
@@ -0,0 +1 @@
+testmultiplexer
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
new file mode 100644
index 0000000..8573ac3
--- /dev/null
+++ b/src/tests/Makefile.am
@@ -0,0 +1,13 @@
+
+bin_PROGRAMS = testmultiplexer
+
+INCLUDES = \
+ -I$(top_srcdir)/src
+
+testmultiplexer_SOURCES = \
+ $(top_srcdir)/src/virtio/multiplexer.cpp \
+ $(top_srcdir)/src/virtio/multiplexer.h \
+ testmultiplexer.cpp \
+ testmultiplexer.h
+
+testmultiplexer_LDADD = -lcppunit
\ No newline at end of file
diff --git a/src/tests/testmultiplexer.cpp b/src/tests/testmultiplexer.cpp
new file mode 100644
index 0000000..8ed77fd
--- /dev/null
+++ b/src/tests/testmultiplexer.cpp
@@ -0,0 +1,109 @@
+/* testmultiplexer.cpp - Copyright (C) 2010 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA. A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "testmultiplexer.h"
+
+#include "virtio/multiplexer.h"
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestCaller.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestSuite.h>
+#include <cppunit/ui/text/TestRunner.h>
+
+const string APINAME("testapifunction");
+
+const char*
+test_callback_function(const char* input)
+{
+ return input;
+}
+
+TestMultiplexer::TestMultiplexer()
+ :TestCase("TestMultiplexer")
+{}
+
+TestSuite*
+TestMultiplexer::suite()
+{
+ CppUnit::TestSuite *result = new CppUnit::TestSuite("TestMultiplexer");
+
+ result->addTest(new CppUnit::TestCaller<TestMultiplexer>
+ ("testBadAPINameGetsNull",
+ &TestMultiplexer::testUnregisteredAPIIsNull));
+ result->addTest(new CppUnit::TestCaller<TestMultiplexer>
+ ("testRegisterAPIMethod",
+ &TestMultiplexer::testRegisterAPIMethod));
+ result->addTest(new CppUnit::TestCaller<TestMultiplexer>
+ ("testEnsureCallingAnUnregisteredAPIFails",
+ &TestMultiplexer::testEnsureCallingAnUnregisteredAPIFails));
+ result->addTest(new CppUnit::TestCaller<TestMultiplexer>
+ ("testEnsureAPIIsCalled",
+ &TestMultiplexer::testEnsureAPIIsCalled));
+
+ return result;
+}
+
+void
+TestMultiplexer::setUp()
+{
+ Multiplexer::instance()->registerAPI(APINAME, test_callback_function);
+}
+
+void
+TestMultiplexer::testUnregisteredAPIIsNull()
+{
+ CPPUNIT_ASSERT(NULL == Multiplexer::instance()->getAPI(APINAME + "!"));
+}
+
+void
+TestMultiplexer::testRegisterAPIMethod()
+{
+ t_apifunction apifunction = test_callback_function;
+
+ CPPUNIT_ASSERT(apifunction == Multiplexer::instance()->getAPI(APINAME));
+}
+
+void
+TestMultiplexer::testEnsureCallingAnUnregisteredAPIFails()
+{
+ string input = string("This is some input");
+ string result = Multiplexer::instance()->invokeAPI(APINAME + "!", input);
+
+ CPPUNIT_ASSERT(string("") == result);
+}
+
+void TestMultiplexer::testEnsureAPIIsCalled()
+{
+ string expected = "This is what I expected";
+ string result = Multiplexer::instance()->invokeAPI(APINAME, expected);
+
+ CPPUNIT_ASSERT(expected == result);
+}
+
+int
+main(int argc, char** argv)
+{
+ CppUnit::TextUi::TestRunner runner;
+
+ runner.addTest(TestMultiplexer::suite());
+ runner.run();
+
+ return 0;
+}
diff --git a/src/tests/testmultiplexer.h b/src/tests/testmultiplexer.h
new file mode 100644
index 0000000..04cb9e5
--- /dev/null
+++ b/src/tests/testmultiplexer.h
@@ -0,0 +1,46 @@
+#ifndef __TESTMULTIPLEXER_H
+#define __TESTMULTIPLEXER_H
+
+/* testmultiplexer.h - Copyright (C) 2010 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA. A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "virtio/multiplexer.h"
+
+#include <cppunit/TestCase.h>
+#include <cppunit/TestSuite.h>
+
+using namespace CppUnit;
+using namespace std;
+
+class TestMultiplexer : public CppUnit::TestCase
+{
+ public:
+ TestMultiplexer();
+
+ static TestSuite* suite();
+
+ void setUp();
+
+ void testUnregisteredAPIIsNull();
+ void testRegisterAPIMethod();
+ void testEnsureCallingAnUnregisteredAPIFails();
+ void testEnsureAPIIsCalled();
+};
+
+#endif
diff --git a/src/virtio/multiplexer.cpp b/src/virtio/multiplexer.cpp
new file mode 100644
index 0000000..79f8b35
--- /dev/null
+++ b/src/virtio/multiplexer.cpp
@@ -0,0 +1,62 @@
+#include "multiplexer.h"
+
+/* multiplexer.cpp - Copyright (C) 2010 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA. A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "multiplexer.h"
+
+// the singleton
+Multiplexer* Multiplexer::_instance = new Multiplexer();
+
+typedef map<string, t_apifunction> APIMAP;
+
+Multiplexer::Multiplexer()
+{}
+
+Multiplexer*
+Multiplexer::instance()
+{
+ return _instance;
+}
+
+void
+Multiplexer::registerAPI(string name, t_apifunction apifunction)
+{
+ _apis.insert(APIMAP::value_type(string(name), apifunction));
+}
+
+t_apifunction
+Multiplexer::getAPI(string name)
+{
+ return (*_apis.find(name)).second;
+}
+
+string
+Multiplexer::invokeAPI(string name, string input)
+{
+ string result = string("");
+ t_apifunction funcptr = (*_apis.find(name)).second;
+
+ if(funcptr)
+ {
+ result = funcptr(input.c_str());
+ }
+
+ return result;
+}
diff --git a/src/virtio/multiplexer.h b/src/virtio/multiplexer.h
new file mode 100644
index 0000000..26a288c
--- /dev/null
+++ b/src/virtio/multiplexer.h
@@ -0,0 +1,48 @@
+#ifndef __MULTIPLEXER_H
+#define __MULTIPLEXER_H
+
+/* multiplexer.h - Copyright (C) 2010 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA. A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include <map>
+#include <string>
+
+using namespace std;
+
+typedef const char*(*t_apifunction)(const char*);
+
+// Multiplexer processes the content received from a remote system.
+class Multiplexer
+{
+ private:
+ Multiplexer();
+
+ static Multiplexer* _instance;
+
+ map<string, t_apifunction> _apis;
+
+ public:
+ static Multiplexer* instance();
+
+ void registerAPI(string apiname, t_apifunction apifunction);
+ t_apifunction getAPI(string apiname);
+ string invokeAPI(string apiname, string input);
+};
+
+#endif
--
1.7.0.1
13 years, 11 months
Why XML-RPC won't work for Matahari/virtio...
by Darryl L. Pierce
The primary reason is that XML-RPC requires HTTP as the transport
between client and server. However, Ryan and I looked xmlrcp-c which
provides a separate means for transport over it's own packet streams.
The limitation here is that it will not work with a character device,
which is what virtio provides to us on the guest side of the connection.
Our goal in this is to avoid reinventing the wheel if some existing
framework can do the job for us. If anybody has recommendations for what
could provide what we need (remote method calls that works with
character devices, with cross platform support for windows guests)
please recommend them.
--
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/
13 years, 11 months
Updated with heartbeat sequence...
by Darryl L. Pierce
This patch supercedes the previous one, introducing a heartbeat sequence
in the API.
It also includes a change to the linking to accomodate changes to qpid.
13 years, 11 months
Supercedes previous patch...
by Darryl L. Pierce
The previous patch, for whatever reason, fails to apply on top of tip.
This patch is reimplemented and, hopefully, fixed.
13 years, 11 months
[PATCH matahari] Adds a check for the qmf-gen executable to the autoconf setup.
by Darryl L. Pierce
Signed-off-by: Darryl L. Pierce <dpierce(a)redhat.com>
---
configure.ac | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/configure.ac b/configure.ac
index 6666c95..42d319b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,6 +7,13 @@ AM_INIT_AUTOMAKE
AC_PROG_CXX
AC_PROG_CC
AC_PROG_CPP
+
+AC_CHECK_PROG(HASQMFGEN, qmf-gen, "yes")
+
+if test x"$HASQMFGEN" = "x"; then
+ AC_MSG_ERROR([Missing QMF schema processor.])
+fi
+
AC_CHECK_HEADERS([arpa/inet.h netinet/in.h sys/ioctl.h sys/socket.h unistd.h libudev.h])
# Checks for typedefs, structures, and compiler characteristics.
--
1.7.0.1
13 years, 11 months
[PATCH matahari] QMF-based heartbeats.
by Darryl L. Pierce
This code allows heartbeat events to be raised on the QMF transport.
Signed-off-by: Darryl L. Pierce <dpierce(a)redhat.com>
---
src/Makefile.am | 2 ++
src/host.cpp | 23 ++++++++---------------
src/qmf/hostagent.cpp | 5 ++++-
src/qmf/hostagent.h | 7 +++++--
src/schema.xml | 6 ++++++
5 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index 498ee72..d830031 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,6 +5,8 @@ sbin_PROGRAMS = matahari
first = qmf/com/redhat/matahari/Host.cpp
generated_file_list = \
+ qmf/com/redhat/matahari/EventHeartbeat.cpp \
+ qmf/com/redhat/matahari/EventHeartbeat.h \
qmf/com/redhat/matahari/Host.h \
qmf/com/redhat/matahari/NetworkDevice.cpp \
qmf/com/redhat/matahari/NetworkDevice.h \
diff --git a/src/host.cpp b/src/host.cpp
index 29b84ec..9b2ad29 100644
--- a/src/host.cpp
+++ b/src/host.cpp
@@ -79,33 +79,26 @@ Host::Host()
}
}
-/*
void
-Host::setup(ManagementAgent* agent, HostAgent* hostAgent)
+Host::update()
{
- // discover the aspects of the host
- _processors.setup(agent, hostAgent);
- _networkdevices = Platform::instance()->get_network_devices();
+ _processors.update();
for(vector<NetworkDeviceAgent>::iterator iter = _networkdevices.begin();
iter != _networkdevices.end();
iter++)
{
- iter->setup(agent, hostAgent);
+ iter->update();
}
-}
-*/
-void
-Host::update()
-{
- _processors.update();
+ time_t __time;
+ time(&__time);
- for(vector<NetworkDeviceAgent>::iterator iter = _networkdevices.begin();
- iter != _networkdevices.end();
+ for(set<HostListener*>::iterator iter = _listeners.begin();
+ iter != _listeners.end();
iter++)
{
- iter->update();
+ (*iter)->heartbeat((unsigned long)__time);
}
}
diff --git a/src/qmf/hostagent.cpp b/src/qmf/hostagent.cpp
index 9807f65..7376f69 100644
--- a/src/qmf/hostagent.cpp
+++ b/src/qmf/hostagent.cpp
@@ -20,7 +20,7 @@
#include "hostagent.h"
#include <qpid/agent/ManagementAgent.h>
-namespace _qmf = qmf::com::redhat::matahari;
+#include "qmf/com/redhat/matahari/EventHeartbeat.h"
HostAgent::HostAgent(Host& host)
:_host(host)
@@ -35,6 +35,8 @@ HostAgent::~HostAgent()
void
HostAgent::setup(ManagementAgent* agent)
{
+ this->_agent = agent;
+
_management_object = new _qmf::Host(agent, this);
agent->addObject(_management_object);
@@ -65,4 +67,5 @@ HostAgent::ManagementMethod(uint32_t method, Args& arguments, string& text)
void
HostAgent::heartbeat(unsigned long timestamp)
{
+ this->_agent->raiseEvent(_qmf::EventHeartbeat(timestamp));
}
diff --git a/src/qmf/hostagent.h b/src/qmf/hostagent.h
index 6d2f2a0..f9a6f8e 100644
--- a/src/qmf/hostagent.h
+++ b/src/qmf/hostagent.h
@@ -31,11 +31,14 @@
using namespace qpid::management;
using namespace std;
+namespace _qmf = qmf::com::redhat::matahari;
+
class HostAgent : public Manageable, public HostListener
{
private:
- qmf::com::redhat::matahari::Host* _management_object;
- Host& _host;
+ _qmf::Host* _management_object;
+ Host& _host;
+ ManagementAgent* _agent;
public:
HostAgent(Host& host);
diff --git a/src/schema.xml b/src/schema.xml
index 206e39b..31abb35 100644
--- a/src/schema.xml
+++ b/src/schema.xml
@@ -14,6 +14,12 @@
</class>
+ <eventArguments>
+ <arg name="timestamp" type="absTime" />
+ </eventArguments>
+
+ <event name="heartbeat" args="timestamp" />
+
<!-- The processor for the node. -->
<class name="Processors">
<property name="host" type="objId" access="RC" desc="The host machine." index="y" references="Host" parentRef="y" />
--
1.6.6.1
13 years, 11 months
[PATCH matahari] Moves the CPU properties into the Host API space.
by Darryl L. Pierce
There was no valid reason to keep this set of APIs in their own agent
and class, so those have been eliminated.
A new HostListener method, HostListener::updated(), was added. It is via
this method that the Host will notify all transports that the load
average statistic is updated on the host.
Signed-off-by: Darryl L. Pierce <dpierce(a)redhat.com>
---
src/Makefile.am | 11 +------
src/host.cpp | 33 +++++++++++++++++-----
src/host.h | 10 ++++---
src/hostlistener.h | 1 +
src/linux_platform.cpp | 10 +++---
src/linux_platform.h | 2 +-
src/main.cpp | 3 --
src/platform.h | 18 +++++-------
src/processors.cpp | 63 -------------------------------------------
src/processors.h | 46 -------------------------------
src/processorslistener.h | 29 -------------------
src/qmf/hostagent.cpp | 9 ++++++
src/qmf/hostagent.h | 1 +
src/qmf/processorsagent.cpp | 49 ---------------------------------
src/qmf/processorsagent.h | 50 ----------------------------------
src/schema.xml | 16 +++++------
16 files changed, 64 insertions(+), 287 deletions(-)
delete mode 100644 src/processors.cpp
delete mode 100644 src/processors.h
delete mode 100644 src/processorslistener.h
delete mode 100644 src/qmf/processorsagent.cpp
delete mode 100644 src/qmf/processorsagent.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 498ee72..7daea07 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,9 +9,7 @@ generated_file_list = \
qmf/com/redhat/matahari/NetworkDevice.cpp \
qmf/com/redhat/matahari/NetworkDevice.h \
qmf/com/redhat/matahari/Package.cpp \
- qmf/com/redhat/matahari/Package.h \
- qmf/com/redhat/matahari/Processors.cpp \
- qmf/com/redhat/matahari/Processors.h
+ qmf/com/redhat/matahari/Package.h
nodist_matahari_SOURCES = $(generated_file_list) $(first)
@@ -26,13 +24,8 @@ matahari_SOURCES = \
networkdevice.h \
platform.cpp \
platform.h \
- processors.cpp \
- processors.h \
- processorslistener.h \
qmf/hostagent.cpp \
- qmf/hostagent.h \
- qmf/processorsagent.cpp \
- qmf/processorsagent.h
+ qmf/hostagent.h
$(generated_file_list): $(generated_file_list)
diff --git a/src/host.cpp b/src/host.cpp
index 29b84ec..6d9a1fe 100644
--- a/src/host.cpp
+++ b/src/host.cpp
@@ -99,14 +99,19 @@ Host::setup(ManagementAgent* agent, HostAgent* hostAgent)
void
Host::update()
{
- _processors.update();
-
for(vector<NetworkDeviceAgent>::iterator iter = _networkdevices.begin();
iter != _networkdevices.end();
iter++)
{
iter->update();
}
+
+ for(set<HostListener*>::iterator iter = _listeners.begin();
+ iter != _listeners.end();
+ iter++)
+ {
+ (*iter)->updated();
+ }
}
void
@@ -121,12 +126,6 @@ Host::removeHostListener(HostListener* listener)
_listeners.erase(listener);
}
-Processors&
-Host::getProcessors()
-{
- return _processors;
-}
-
string
Host:: getUUID() const
{
@@ -163,6 +162,24 @@ Host::isBeeping() const
return _beeping;
}
+string
+Host::getCPUModel() const
+{
+ return Platform::instance()->getCPUModel();
+}
+
+unsigned int
+Host::getNumberOfCPUCores() const
+{
+ return Platform::instance()->getNumberOfCPUCores();
+}
+
+double
+Host::getLoadAverage() const
+{
+ return Platform::instance()->getLoadAverage();
+}
+
void
Host::identify(const int iterations)
{
diff --git a/src/host.h b/src/host.h
index bcb8c12..f21c86c 100644
--- a/src/host.h
+++ b/src/host.h
@@ -24,7 +24,6 @@
#include <set>
#include "hostlistener.h"
-#include "processors.h"
#include "networkdevice.h"
using namespace std;
@@ -42,7 +41,6 @@ class Host
unsigned int _memory;
bool _beeping;
- Processors _processors;
vector<NetworkDeviceAgent> _networkdevices;
set<HostListener*> _listeners;
@@ -55,14 +53,18 @@ class Host
void addHostListener(HostListener*);
void removeHostListener(HostListener*);
- Processors& getProcessors();
-
+ // general host properties
string getUUID() const;
string getHostname() const;
string getHypervisor() const;
string getArchitecture() const;
unsigned int getMemory() const;
+ // CPU properties
+ string getCPUModel() const;
+ unsigned int getNumberOfCPUCores() const;
+ double getLoadAverage() const;
+
bool isBeeping() const;
void identify(const int iterations);
void shutdown();
diff --git a/src/hostlistener.h b/src/hostlistener.h
index 298e51d..0d09594 100644
--- a/src/hostlistener.h
+++ b/src/hostlistener.h
@@ -27,6 +27,7 @@
class HostListener
{
public:
+ virtual void updated() = 0;
virtual void heartbeat(unsigned long timestamp) = 0;
};
diff --git a/src/linux_platform.cpp b/src/linux_platform.cpp
index fbcfdb9..b05a327 100644
--- a/src/linux_platform.cpp
+++ b/src/linux_platform.cpp
@@ -36,7 +36,7 @@ extern "C" {
LinuxPlatform::LinuxPlatform()
{
- int core_count = 0;
+ int cpu_count = 0;
string model = "unknown";
struct udev* udev = udev_new();
@@ -50,9 +50,9 @@ LinuxPlatform::LinuxPlatform()
udev_list_entry_foreach(entry, entries)
{
- core_count++;
+ cpu_count++;
}
- set_number_of_cores(core_count);
+ setNumberOfCPUCores(cpu_count);
}
udev_enumerate_unref(enumerator);
@@ -100,7 +100,7 @@ LinuxPlatform::LinuxPlatform()
}
else
{
- if(name == "model name") set_processor_model(value);
+ if(name == "model name") setCPUModel(value);
}
}
}
@@ -109,7 +109,7 @@ LinuxPlatform::LinuxPlatform()
}
double
-LinuxPlatform::get_load_average() const
+LinuxPlatform::getLoadAverage() const
{
double load_average;
ifstream input;
diff --git a/src/linux_platform.h b/src/linux_platform.h
index 095bc08..a66cbe4 100644
--- a/src/linux_platform.h
+++ b/src/linux_platform.h
@@ -32,7 +32,7 @@ class LinuxPlatform : public Platform
LinuxPlatform();
virtual ~LinuxPlatform() {}
- virtual double get_load_average() const;
+ virtual double getLoadAverage() const;
virtual vector<NetworkDeviceAgent> get_network_devices() const;
};
diff --git a/src/main.cpp b/src/main.cpp
index f45353a..3ab4147 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -34,7 +34,6 @@
#include "host.h"
#include "qmf/hostagent.h"
-#include "qmf/processorsagent.h"
#include "qmf/com/redhat/matahari/Package.h"
@@ -82,7 +81,6 @@ main(int argc, char **argv)
ManagementAgent *agent;
Host host;
HostAgent hostAgent(host);
- ProcessorsAgent processorsAgent(host.getProcessors());;
struct option opt[] = {
{"help", no_argument, NULL, 'h'},
@@ -185,7 +183,6 @@ main(int argc, char **argv)
// Get the info and post it to the broker
hostAgent.setup(agent);
- processorsAgent.setup(agent, &hostAgent);
while(1)
{
diff --git a/src/platform.h b/src/platform.h
index 54fbe37..ba70378 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -37,28 +37,24 @@ class Platform
private:
static Platform* _instance;
- string processor_model;
- unsigned int number_of_cores;
+ string _cpu_model;
+ unsigned int _cpu_cores;
protected:
Platform() {}
virtual~ Platform() {}
- void set_processor_model(const string model) { processor_model = model; }
- void set_number_of_cores(const int number) { number_of_cores = number; }
+ void setCPUModel(const string model) { _cpu_model = model; }
+ void setNumberOfCPUCores(const int cores) { _cpu_cores = cores; }
public:
// the singleton instance
static Platform* instance();
- // returns text describing the processor model.
- string get_processor_model() const { return processor_model; }
+ string getCPUModel() const { return _cpu_model; }
+ unsigned int getNumberOfCPUCores() const { return _cpu_cores; }
- // returns the number of cores in the processor.
- int get_number_of_cores() const { return number_of_cores; }
-
- // returns the load average for the platform
- virtual double get_load_average() const = 0;
+ virtual double getLoadAverage() const = 0;
// returns the list of network devices for this platform
virtual vector<NetworkDeviceAgent> get_network_devices() const = 0;
diff --git a/src/processors.cpp b/src/processors.cpp
deleted file mode 100644
index 1850aba..0000000
--- a/src/processors.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/* processor.cpp - Copyright (C) 2010 Red Hat, Inc.
- * Written by Darryl L. Pierce <dpierce(a)redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA. A copy of the GNU General Public License is
- * also available at http://www.gnu.org/copyleft/gpl.html.
- */
-
-#include "processors.h"
-#include "platform.h"
-
-void
-Processors::addProcessorsListener(ProcessorsListener* listener)
-{
- _listeners.insert(listener);
-}
-
-void
-Processors::removeProcessorsListener(ProcessorsListener* listener)
-{
- _listeners.erase(listener);
-}
-
-void
-Processors::update()
-{
- for(set<ProcessorsListener*>::iterator iter = _listeners.begin();
- iter != _listeners.end();
- iter++)
- {
- (*iter)->updated();
- }
-}
-
-string
-Processors::getModel() const
-{
- return Platform::instance()->get_processor_model();
-}
-
-
-unsigned int
-Processors::getNumberOfCores() const
-{
- return Platform::instance()->get_number_of_cores();
-}
-
-float
-Processors::getLoadAverage() const
-{
- return Platform::instance()->get_load_average();
-}
diff --git a/src/processors.h b/src/processors.h
deleted file mode 100644
index e69a6ee..0000000
--- a/src/processors.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __PROCESSORS_H
-#define __PROCESSORS_H
-
-/* processor.h - Copyright (C) 2010 Red Hat, Inc.
- * Written by Darryl L. Pierce <dpierce(a)redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA. A copy of the GNU General Public License is
- * also available at http://www.gnu.org/copyleft/gpl.html.
- */
-
-#include <set>
-#include <string>
-
-#include "processorslistener.h"
-
-using namespace std;
-
-class Processors
-{
- private:
- set<ProcessorsListener*> _listeners;
-
- public:
- void addProcessorsListener(ProcessorsListener* listener);
- void removeProcessorsListener(ProcessorsListener* listener);
-
- void update();
-
- string getModel() const;
- unsigned int getNumberOfCores() const;
- float getLoadAverage() const;
-};
-
-#endif
diff --git a/src/processorslistener.h b/src/processorslistener.h
deleted file mode 100644
index d6818c8..0000000
--- a/src/processorslistener.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __PROCESSORSLISTENER_H
-#define __PROCESSORSLISTENER_H
-
-/* processorslistener.h - Copyright (C) 2009 Red Hat, Inc.
- * Written by Darryl Pierce <dpierce(a)redhat.com>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA. A copy of the GNU General Public License is
- * also available at http://www.gnu.org/copyleft/gpl.html.
- */
-
-class ProcessorsListener
-{
- public:
- virtual void updated() = 0;
-};
-
-#endif
diff --git a/src/qmf/hostagent.cpp b/src/qmf/hostagent.cpp
index 9807f65..1baac73 100644
--- a/src/qmf/hostagent.cpp
+++ b/src/qmf/hostagent.cpp
@@ -44,6 +44,9 @@ HostAgent::setup(ManagementAgent* agent)
_management_object->set_arch(_host.getArchitecture());
_management_object->set_memory(_host.getMemory());
_management_object->set_beeping(_host.isBeeping());
+
+ _management_object->set_cpu_model(_host.getCPUModel());
+ _management_object->set_cpu_cores(_host.getNumberOfCPUCores());
}
Manageable::status_t
@@ -63,6 +66,12 @@ HostAgent::ManagementMethod(uint32_t method, Args& arguments, string& text)
}
void
+HostAgent::updated()
+{
+ _management_object->set_load_average(_host.getLoadAverage());
+}
+
+void
HostAgent::heartbeat(unsigned long timestamp)
{
}
diff --git a/src/qmf/hostagent.h b/src/qmf/hostagent.h
index 6d2f2a0..9d01f2c 100644
--- a/src/qmf/hostagent.h
+++ b/src/qmf/hostagent.h
@@ -45,6 +45,7 @@ class HostAgent : public Manageable, public HostListener
ManagementObject* GetManagementObject() const { return _management_object; }
status_t ManagementMethod(uint32_t method, Args& arguments, string& text);
+ virtual void updated();
virtual void heartbeat(unsigned long timestamp);
};
diff --git a/src/qmf/processorsagent.cpp b/src/qmf/processorsagent.cpp
deleted file mode 100644
index c1703de..0000000
--- a/src/qmf/processorsagent.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/* processorsagent.cpp - Copyright (C) 2009 Red Hat, Inc.
- * Written by Arjun Roy <arroy(a)redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA. A copy of the GNU General Public License is
- * also available at http://www.gnu.org/copyleft/gpl.html.
- */
-
-#include "processorsagent.h"
-#include <qpid/agent/ManagementAgent.h>
-
-namespace _qmf = qmf::com::redhat::matahari;
-
-ProcessorsAgent::ProcessorsAgent(Processors& processors)
- :_processors(processors)
-{
- processors.addProcessorsListener(this);
-}
-
-ProcessorsAgent::~ProcessorsAgent()
-{
-}
-
-void
-ProcessorsAgent::setup(ManagementAgent* agent, HostAgent* parent)
-{
- _management_object = new _qmf::Processors(agent, this, parent);
- agent->addObject(_management_object);
-
- _management_object->set_model(this->_processors.getModel());
- _management_object->set_cores(this->_processors.getNumberOfCores());
-}
-
-void
-ProcessorsAgent::updated()
-{
- _management_object->set_load_average(this->_processors.getLoadAverage());
-}
diff --git a/src/qmf/processorsagent.h b/src/qmf/processorsagent.h
deleted file mode 100644
index 1d814d4..0000000
--- a/src/qmf/processorsagent.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef __PROCESSORSAGENT_H
-#define __PROCESSORSAGENT_H
-
-/* processoragent.h - Copyright (C) 2010 Red Hat, Inc.
- * Written by Darryl L. Pierce <dpierce(a)redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA. A copy of the GNU General Public License is
- * also available at http://www.gnu.org/copyleft/gpl.html.
- */
-
-#include <qpid/management/Manageable.h>
-#include <qpid/management/ManagementObject.h>
-
-#include "processors.h"
-#include "processorslistener.h"
-#include "qmf/com/redhat/matahari/Processors.h"
-#include "qmf/hostagent.h"
-
-using namespace qpid::management;
-
-class ProcessorsAgent : public Manageable, public ProcessorsListener
-{
- private:
- qmf::com::redhat::matahari::Processors* _management_object;
-
- Processors& _processors;
-
- public:
- ProcessorsAgent(Processors& processors);
- virtual ~ProcessorsAgent();
-
- void setup(ManagementAgent* agent, HostAgent* parent);
- ManagementObject* GetManagementObject(void) const { return _management_object; }
-
- virtual void updated();
-};
-
-#endif
diff --git a/src/schema.xml b/src/schema.xml
index 206e39b..fd83ac1 100644
--- a/src/schema.xml
+++ b/src/schema.xml
@@ -2,6 +2,7 @@
<class name="Host">
+ <!-- general properties -->
<property name="uuid" type="sstr" access="RO" desc="Host UUID" index="y"/>
<property name="hostname" type="sstr" access="RO" desc="Hostname"/>
<property name="memory" type="int64" access="RO" desc="Amount of primary memory for host (kb)" unit="kb"/>
@@ -9,20 +10,17 @@
<property name="arch" type="sstr" access="RO" desc="Architecture of host"/>
<property name="beeping" type="bool" access="RW" desc="speaker beep loop active? (used to identify host)"/>
+ <!-- CPU properties -->
+ <property name="cpu_model" type="lstr" access="RO" desc="The process model description." />
+ <property name="cpu_cores" type="uint8" access="RO" desc="The number of processor cores." />
+ <statistic name="load_average" type="double" desc="The current processing load average." />
+
+ <!-- APIs -->
<method name="shutdown" desc="Shutdown node" />
<method name="reboot" desc="Reboot node" />
</class>
- <!-- The processor for the node. -->
- <class name="Processors">
- <property name="host" type="objId" access="RC" desc="The host machine." index="y" references="Host" parentRef="y" />
- <property name="model" type="lstr" access="RO" desc="The processor label." />
- <property name="cores" type="int8" access="RO" desc="The number of cores." />
-
- <statistic name="load_average" type="float" desc="The processing load average." />
- </class>
-
<!-- represents a physical network device -->
<class name="NetworkDevice">
<property name="host" type="objId" access="RC" desc="The host machine." index="y" references="Host" parentRef="y" />
--
1.6.6.1
13 years, 11 months
Squashed commits...
by Darryl L. Pierce
Refactoring the previous patch ended up creating two deltas. This
patch pushes them both together into a single commit.
13 years, 11 months
[PATCH matahari] Moved the follow platform details to the Platform class to keep the details abstract and platform-independent:
by Darryl L. Pierce
* UUID
* hostname
* hardware architecture
* total system memory
* hypervisor
Signed-off-by: Darryl L. Pierce <dpierce(a)redhat.com>
---
src/host.cpp | 61 ++++-------------------------------------------
src/linux_platform.cpp | 58 +++++++++++++++++++++++++++++++++++++++++----
src/platform.h | 37 ++++++++++++++++++++++++----
3 files changed, 90 insertions(+), 66 deletions(-)
diff --git a/src/host.cpp b/src/host.cpp
index 34d4550..b9b4a7f 100644
--- a/src/host.cpp
+++ b/src/host.cpp
@@ -19,10 +19,7 @@
#include <fstream>
-#include <libvirt/libvirt.h>
#include <qpid/management/Manageable.h>
-#include <sys/sysinfo.h>
-#include <sys/utsname.h>
#include "host.h"
#include "platform.h"
@@ -51,58 +48,12 @@ HostAgent::setup(ManagementAgent* agent)
iter->setup(agent, this);
}
- struct utsname details;
- string uuid = "Unknown";
- string hostname = "Unknown";
- string hypervisor = "Unknown";
- string architecture = "None";
- unsigned long memory = 0;
- bool beeping = false;
-
- ifstream input("/var/lib/dbus/machine-id");
-
- if(input.is_open())
- {
- getline(input, uuid);
- input.close();
- }
-
- if(!uname(&details))
- {
- hostname = string(details.nodename);
- architecture = string(details.machine);
- }
- else
- {
- throw runtime_error("Unable to retrieve system details");
- }
-
- virConnectPtr lvconn = virConnectOpenReadOnly(NULL);
-
- if(lvconn)
- {
- hypervisor = string(virConnectGetType(lvconn));
- virConnectClose(lvconn);
- }
-
- struct sysinfo sysinf;
- if(!sysinfo(&sysinf))
- {
- memory = sysinf.totalram / 1024L;
- }
- else
- {
- throw runtime_error("Unable to retrieve system memory details.");
- }
-
- cout << "memory: " << memory << endl;
-
- management_object->set_uuid(uuid);
- management_object->set_hostname(hostname);
- management_object->set_hypervisor(hypervisor);
- management_object->set_arch(architecture);
- management_object->set_memory(memory);
- management_object->set_beeping(beeping);
+ management_object->set_uuid(Platform::instance()->getUUID());
+ management_object->set_hostname(Platform::instance()->getHostname());
+ management_object->set_hypervisor(Platform::instance()->getHypervisor());
+ management_object->set_arch(Platform::instance()->getArchitecture());
+ management_object->set_memory(Platform::instance()->getMemory());
+ management_object->set_beeping(false);
}
void
diff --git a/src/linux_platform.cpp b/src/linux_platform.cpp
index fbcfdb9..805f071 100644
--- a/src/linux_platform.cpp
+++ b/src/linux_platform.cpp
@@ -21,11 +21,14 @@
#include <iomanip>
#include <iostream>
#include <dirent.h>
+#include <libvirt/libvirt.h>
#include <net/if.h>
#include <pcre.h>
#include <stdexcept>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/sysinfo.h>
+#include <sys/utsname.h>
// TODO remove this wrapper once rhbz#583747 is fixed
extern "C" {
@@ -39,6 +42,50 @@ LinuxPlatform::LinuxPlatform()
int core_count = 0;
string model = "unknown";
+ string uuid;
+ ifstream* input;
+
+ input = new ifstream("/var/lib/dbus/machine-id");
+
+ if(input->is_open())
+ {
+ getline(*input, uuid);
+ input->close();
+ this->setUUID(uuid);
+ }
+ input->close();
+ delete input;
+
+ struct utsname details;
+
+ if(!uname(&details))
+ {
+ this->setHostname(string(details.nodename));
+ this->setArchitecture(string(details.machine));
+ }
+ else
+ {
+ throw runtime_error("Unable to retrieve system details");
+ }
+
+ virConnectPtr lvconn = virConnectOpenReadOnly(NULL);
+
+ if(lvconn)
+ {
+ this->setHypervisor(string(virConnectGetType(lvconn)));
+ virConnectClose(lvconn);
+ }
+
+ struct sysinfo sysinf;
+ if(!sysinfo(&sysinf))
+ {
+ this->setMemory(sysinf.totalram / 1024L);
+ }
+ else
+ {
+ throw runtime_error("Unable to retrieve system memory details.");
+ }
+
struct udev* udev = udev_new();
struct udev_enumerate* enumerator = udev_enumerate_new(udev);
@@ -58,8 +105,8 @@ LinuxPlatform::LinuxPlatform()
udev_enumerate_unref(enumerator);
udev_unref(udev);
- ifstream input("/proc/cpuinfo");
- if(input.is_open())
+ input = new ifstream("/proc/cpuinfo");
+ if(input->is_open())
{
string regexstr = "(.*\\S)\\s*:\\s*(\\S.*)";
int expected = 3;
@@ -73,11 +120,11 @@ LinuxPlatform::LinuxPlatform()
regex = pcre_compile(regexstr.c_str(), 0, &pcre_error, &pcre_error_offset, NULL);
if(!regex) { throw runtime_error("Unable to compile regular expression."); }
- while(!input.eof() && !done)
+ while(!input->eof() && !done)
{
string line;
- getline(input, line);
+ getline(*input, line);
int match = pcre_exec(regex, NULL, line.c_str(), line.length(),
0, PCRE_NOTEMPTY,found, expected * 3);
@@ -104,7 +151,8 @@ LinuxPlatform::LinuxPlatform()
}
}
}
- input.close();
+ input->close();
+ delete input;
}
}
diff --git a/src/platform.h b/src/platform.h
index 54fbe37..1a976a6 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -37,25 +37,50 @@ class Platform
private:
static Platform* _instance;
- string processor_model;
- unsigned int number_of_cores;
+ string _uuid;
+ string _hostname;
+ string _architecture;
+ string _hypervisor;
+ unsigned long _memory;
+ string _processor_model;
+ unsigned int _number_of_cores;
protected:
Platform() {}
virtual~ Platform() {}
- void set_processor_model(const string model) { processor_model = model; }
- void set_number_of_cores(const int number) { number_of_cores = number; }
+ void setUUID(const string uuid) { _uuid = uuid; }
+ void setHostname(const string hostname) { _hostname = hostname; }
+ void setArchitecture(const string arch) { _architecture = arch; }
+ void setHypervisor(const string hypervisor) { _hypervisor = hypervisor; }
+ void setMemory(const unsigned long memory) { _memory = memory; }
+ void set_processor_model(const string model) { _processor_model = model; }
+ void set_number_of_cores(const int number) { _number_of_cores = number; }
public:
// the singleton instance
static Platform* instance();
+ // returns the UUID for the installation
+ string getUUID() const { return _uuid; }
+
+ // returns the fully qualified hostname
+ string getHostname() const { return _hostname; }
+
+ // returns the system architecture
+ string getArchitecture() const { return _architecture; }
+
+ // returns the hypervisor
+ string getHypervisor() const { return _hypervisor; }
+
+ // returns the total system memory
+ unsigned long getMemory() const { return _memory; }
+
// returns text describing the processor model.
- string get_processor_model() const { return processor_model; }
+ string get_processor_model() const { return _processor_model; }
// returns the number of cores in the processor.
- int get_number_of_cores() const { return number_of_cores; }
+ int get_number_of_cores() const { return _number_of_cores; }
// returns the load average for the platform
virtual double get_load_average() const = 0;
--
1.6.6.1
13 years, 11 months
Replacement patch...
by Darryl L. Pierce
This patch supercedes the previous patch. It uses an event listener model
rather than peer object notifications.
13 years, 11 months