- These changes incorporate the responses from ML https://fedorahosted.org/pipermail/matahari/2011-July/001434.html
Signed-off-by: Adam Stokes astokes@fedoraproject.org --- src/include/matahari/sysconfig.h | 67 ++++++++++++++ src/lib/CMakeLists.txt | 11 ++- src/lib/sysconfig_linux.c | 152 ++++++++++++++++++++++++++++++++ src/sysconfig/CMakeLists.txt | 30 +++++++ src/sysconfig/schema.xml | 35 ++++++++ src/sysconfig/sysconfig-console.cpp | 96 ++++++++++++++++++++ src/sysconfig/sysconfig-qmf.cpp | 163 +++++++++++++++++++++++++++++++++++ src/tests/CMakeLists.txt | 6 +- src/tests/mh_api_sysconfig.h | 34 +++++++ 9 files changed, 586 insertions(+), 8 deletions(-) create mode 100644 src/include/matahari/sysconfig.h create mode 100644 src/lib/sysconfig_linux.c create mode 100644 src/sysconfig/CMakeLists.txt create mode 100644 src/sysconfig/schema.xml create mode 100644 src/sysconfig/sysconfig-console.cpp create mode 100644 src/sysconfig/sysconfig-qmf.cpp create mode 100644 src/tests/mh_api_sysconfig.h
diff --git a/src/include/matahari/sysconfig.h b/src/include/matahari/sysconfig.h new file mode 100644 index 0000000..6eca232 --- /dev/null +++ b/src/include/matahari/sysconfig.h @@ -0,0 +1,67 @@ +/* sysconfig.h - Copyright (C) 2011 Red Hat, Inc. + * Written by Adam Stokes astokes@fedoraproject.org + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * This software 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * \file + * \brief Config API + * \ingroup coreapi + */ + +#ifndef __MH_SYSCONFIG_H__ +#define __MH_SYSCONFIG_H__ + +#include <stdint.h> +/*! Supported FLAGS */ +#define MH_SYSCONFIG_FLAG_FORCE (1 << 0) + +/** + * Download and process URI for configuration + * + * \param[in] uri the url of configuration item + * \param[in] flags flags used + * \param[in] scheme the type of configuration i.e. puppet + * + * \return 0 for success -1 for fail + */ +extern int mh_sysconfig_run_uri(const char *uri, uint32_t flags, const char *scheme); + +/** + * Process a text blob + * + * \param[in] string the text blob to process, accepts a range of data from XML to Puppet classes + * \param[in] flags flags used + * \param[in] scheme the type of configuration i.e. puppet + * + * \return 0 for success -1 for fail + */ +extern int mh_sysconfig_run_string(const char *string, uint32_t flags, const char *scheme); + +/** + * Query against a configuration object on the system + * + * \param[in] query the query command used + * \param[in] flags flags used + * \param[in] scheme the type of configuration i.e. puppet + * \param[out] data the data found from query parameter + * + * \return data the result found from query + */ +extern const char * +mh_sysconfig_query(const char *query, uint32_t flags, const char *scheme); + +#endif // __MH_SYSCONFIG_H__ diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index cf37cf3..6a6c242 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,6 +1,6 @@ # Library
-set(LIBS mcommon mhost mnetwork mservice mpostboot) +set(LIBS mcommon mhost mnetwork mservice msysconfig) include_directories(${pcre_INCLUDE_DIRS})
# See http://sourceware.org/autobook/autobook/autobook_91.html for @@ -22,9 +22,9 @@ add_library (mservice SHARED services.c services_${VARIANT}.c) set_target_properties(mservice PROPERTIES SOVERSION 1.0.0) target_link_libraries(mservice ${pcre_LIBRARIES} mcommon ${SIGAR} ${glib_LIBRARIES})
-add_library (mpostboot SHARED postboot.c) -set_target_properties(mpostboot PROPERTIES SOVERSION 1.0.0) -target_link_libraries(mpostboot ${pcre_LIBRARIES} mcommon ${glib_LIBRARIES}) +add_library (msysconfig SHARED sysconfig_${VARIANT}.c) +set_target_properties(msysconfig PROPERTIES SOVERSION 1.0.0) +target_link_libraries(msysconfig ${pcre_LIBRARIES} mcommon ${glib_LIBRARIES})
if(WIN32) foreach (lib ${LIBS}) @@ -33,7 +33,8 @@ if(WIN32) endforeach (lib ${LIBS}) else(WIN32) foreach (lib ${LIBS}) - install(TARGETS ${lib} DESTINATION lib${LIB_SUFFIX}) + target_link_libraries(${lib} resolv curl) + install(TARGETS ${lib} DESTINATION lib${LIB_SUFFIX}) endforeach (lib ${LIBS}) endif(WIN32)
diff --git a/src/lib/sysconfig_linux.c b/src/lib/sysconfig_linux.c new file mode 100644 index 0000000..6c40a4e --- /dev/null +++ b/src/lib/sysconfig_linux.c @@ -0,0 +1,152 @@ +/* sysconfig_linux.c - Copyright (C) 2011 Red Hat, Inc. + * Written by Adam Stokes astokes@fedoraproject.org + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * This software 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef WIN32 +#include "config.h" +#include <stddef.h> +#endif + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <glib.h> +#include <curl/curl.h> +#include "matahari/logging.h" +#include "matahari/sysconfig.h" +#include "matahari/utilities.h" + + +MH_TRACE_INIT_DATA(mh_sysconfig); + +static int +download(const char *uri, FILE *fp) +{ + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_DEFAULT); + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, uri); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + res = curl_easy_perform(curl); + + if (CURLE_OK != res) { + return -1; + } + } + curl_global_cleanup(); + return 0; +} + + +static int +mh_sysconfig_run_puppet(const char *uri, const char *data) +{ + gboolean ret; + GError *error; + char filename[PATH_MAX + 1]; + gchar cmd[PATH_MAX]; + int fd; + FILE *fp; + + if (uri != NULL) { + strncpy(filename, "puppet_conf_XXXXXX", sizeof(filename) -1); + fd = mkstemp(filename); + if (fd < 0) { + return -1; + } + fp = fdopen(fd, "w+b"); + if (fp == NULL) { + return -1; + } + if ((download(uri, fp)) != 0) { + fclose(fp); + return -1; + } + fclose(fp); + } else if (data != NULL) { + strncpy(filename,"puppet_conf_blob", sizeof(filename) -1); + g_file_set_contents(filename, data, strlen(data), NULL); + } else { + return -1; + } + + g_snprintf(cmd, sizeof(cmd), "puppet %s", filename); + ret = g_spawn_async(NULL, (gchar **)cmd, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, &error); + fprintf(stderr, "bool: %d", ret); + if (ret == FALSE) { + g_error_free(error); + return -1; + } + return 0; +} + +static int +mh_sysconfig_run_augeas(const char *query, const char *data) +{ + mh_warn("not implemented\n"); + return 0; +} + +static const char * +mh_sysconfig_query_augeas(const char *query) +{ + const char *data = NULL; + mh_warn("not implemented\n"); + return data; +} + +int +mh_sysconfig_run_uri(const char *uri, uint32_t flags, const char *scheme) +{ + int rc = 0; + + if (strcasecmp(scheme, "puppet") == 0) { + rc = mh_sysconfig_run_puppet(uri, NULL); + } else { + rc = -1; + } + return rc; +} + +int +mh_sysconfig_run_string(const char *data, uint32_t flags, const char *scheme) +{ + int rc = 0; + + if (strcasecmp(scheme, "puppet") == 0) { + rc = mh_sysconfig_run_puppet(NULL, data); + } else { + rc = -1; + } + return rc; +} + +const char * +mh_sysconfig_query(const char *query, uint32_t flags, const char *scheme) +{ + const char *data = NULL; + + if (strcasecmp(scheme, "augeas") == 0) { + data = mh_sysconfig_query_augeas(query); + } + + return data; +} diff --git a/src/sysconfig/CMakeLists.txt b/src/sysconfig/CMakeLists.txt new file mode 100644 index 0000000..1d9fba8 --- /dev/null +++ b/src/sysconfig/CMakeLists.txt @@ -0,0 +1,30 @@ +set(BASE "sysconfig") +set(BASE_LIB "m${BASE}") +set(QMF_AGENT "matahari-qmf-${BASE}d") +set(QMF_CONSOLE "matahari-qmf-${BASE}-consoled") + +# QMF daemon +if(WITH-QMF) + set(SCHEMA_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/qmf/org/matahariproject/QmfPackage.cpp) + generate_qmf_schemas(${CMAKE_CURRENT_SOURCE_DIR}/schema.xml ${SCHEMA_SOURCES}) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + add_executable(${QMF_AGENT} ${BASE}-qmf.cpp ${SCHEMA_SOURCES}) + add_executable(${QMF_CONSOLE} ${BASE}-console.cpp) + + target_link_libraries(${QMF_AGENT} ${BASE_LIB} mcommon_qmf) + target_link_libraries(${QMF_CONSOLE} mcommon_qmf) + + if(NOT WIN32) + configure_file(${CMAKE_SOURCE_DIR}/matahari.init.in ${CMAKE_CURRENT_BINARY_DIR}/matahari-${BASE}) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/matahari-${BASE} DESTINATION ${initdir}) + # Override BASE for matahari-sysconfig-console + unset(BASE) + set(BASE "sysconfig-console") + configure_file(${CMAKE_SOURCE_DIR}/matahari.init.in ${CMAKE_CURRENT_BINARY_DIR}/matahari-${BASE}) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/matahari-${BASE} DESTINATION ${initdir}) + endif(NOT WIN32) + + install(TARGETS ${QMF_AGENT} DESTINATION sbin) + install(TARGETS ${QMF_CONSOLE} DESTINATION sbin) +endif(WITH-QMF) diff --git a/src/sysconfig/schema.xml b/src/sysconfig/schema.xml new file mode 100644 index 0000000..d5c52aa --- /dev/null +++ b/src/sysconfig/schema.xml @@ -0,0 +1,35 @@ +<schema package="org.matahariproject"> + + <!-- Config API --> + <class name="Sysconfig"> + <property name="uuid" type="sstr" access="RO" desc="Host UUID" /> + <property name="hostname" type="sstr" access="RO" desc="Hostname" index="y"/> + <property name="is_postboot_configured" type="uint32" access="RO" desc="Check if agent is configured." /> + + <statistic name="qmf-gen-no-crash" type="absTime" desc="Dummy stat to stop qmf-gen from crashing." /> + + <method name="run_uri" desc="Send configure uri method"> + <arg name="uri" dir="I" type="sstr" /> + <arg name="scheme" dir="I" type="sstr" /> + <arg name="key" dir="I" type="sstr" /> + <arg name="flags" dir="I" type="uint32" /> + </method> + + <method name="run_string" desc="Send configure text method"> + <arg name="text" dir="I" type="sstr" /> + <arg name="scheme" dir="I" type="sstr" /> + <arg name="key" dir="I" type="sstr" /> + <arg name="flags" dir="I" type="uint32" /> + </method> + + <method name="query" desc="Perform query lookup"> + <arg name="text" dir="I" type="sstr" /> + <arg name="scheme" dir="I" type="sstr" /> + <arg name="flags" dir="I" type="uint32" /> + </method> + + <method name="is_configured" desc="Check if system is configured"> + <arg name="key" dir="I" type="sstr" /> + </method> + </class> +</schema> diff --git a/src/sysconfig/sysconfig-console.cpp b/src/sysconfig/sysconfig-console.cpp new file mode 100644 index 0000000..cc9f4f0 --- /dev/null +++ b/src/sysconfig/sysconfig-console.cpp @@ -0,0 +1,96 @@ +/* config-console.cpp - Copyright (c) 2011 Red Hat, Inc. + * Written by Adam Stokes astokes@fedoraproject.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef WIN32 +#include "config.h" +#endif + +#include <qpid/messaging/Connection.h> +#include <qpid/messaging/Duration.h> +#include <qmf/ConsoleSession.h> +#include <qmf/ConsoleEvent.h> +#include <qmf/Agent.h> +#include <qmf/Data.h> +#include <qmf/DataAddr.h> +#include <qmf/Query.h> +#include <qpid/types/Variant.h> + +#include "matahari/mh_agent.h" + +#include <string> +#include <iostream> +#include <sstream> + +extern "C" { +#include "matahari/logging.h" +} + +using namespace std; +using namespace qmf; +using qpid::types::Variant; +using qpid::messaging::Duration; + +int main(int argc, char **argv) +{ + qpid::types::Variant::Map options; + qpid::types::Variant::Map callOptions; + string sessionOptions; + ConsoleEvent event; + Agent agent; + + mh_log_init("sysconfig-console", LOG_TRACE, TRUE); + + mh_add_option('U', required_argument, "uri", "URI of configuration", &options, NULL); + + qpid::types::Variant::Map url = mh_parse_options("sysconfig-console", argc, argv, options); + + callOptions["uri"] = options["uri"]; + + mh_log_init("sysconfig-console", mh_log_level, mh_log_level > LOG_INFO); + + qpid::messaging::Connection connection(url["uri"], options); + connection.open(); + + ConsoleSession session(connection, sessionOptions); + // Only filter connecting agents under matahariproject.org vendor and Config product + session.setAgentFilter("[and, [eq, _vendor, [quote, 'matahariproject.org']], [eq, _product, [quote, 'Sysconfig']]]"); + session.open(); + + while(session.getAgentCount() == 0) { + g_usleep(1000); + } + + while (true) { + if(session.nextEvent(event)) { + switch(event.getType()) { + case CONSOLE_AGENT_ADD: + { + agent = event.getAgent(); + DataAddr agent_event_addr("config", agent.getName(), 0); + ConsoleEvent result(agent.callMethod("configure", + callOptions, + agent_event_addr)); + } + break; + default: + break; + } + } + } + return 0; +} diff --git a/src/sysconfig/sysconfig-qmf.cpp b/src/sysconfig/sysconfig-qmf.cpp new file mode 100644 index 0000000..86b37b8 --- /dev/null +++ b/src/sysconfig/sysconfig-qmf.cpp @@ -0,0 +1,163 @@ +/* config-qmf.cpp - Copyright (C) 2011 Red Hat, Inc. + * Written by Adam Stokes astokes@fedoraproject.org + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * This software 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * \file + * \brief Sysconfig QMF Agent + */ + +#ifndef WIN32 +#include "config.h" +#endif + +#include "matahari/mh_agent.h" + +#include "qmf/org/matahariproject/QmfPackage.h" + +#include <qpid/agent/ManagementAgent.h> + +extern "C" { +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <glib.h> +#include <glib/gstdio.h> +#include <glib/gprintf.h> +#include "matahari/sysconfig.h" +#include "matahari/logging.h" +#include "matahari/network.h" +#include "matahari/host.h" +#include <sigar.h> +#include <sigar_format.h> +}; + +static const char configured_fn[] = "/var/lib/matahari/.is_configured"; + +class ConfigAgent : public MatahariAgent +{ +private: + qmf::org::matahariproject::PackageDefinition _package; +public: + virtual int setup(qmf::AgentSession session); + virtual gboolean invoke(qmf::AgentSession session, qmf::AgentEvent event, + gpointer user_data); +}; + +int +main(int argc, char **argv) +{ + ConfigAgent agent; + int rc = agent.init(argc, argv, "Sysconfig"); + if (rc == 0) { + agent.run(); + } + return rc; +} + +int +ConfigAgent::setup(qmf::AgentSession session) +{ + _package.configure(session); + _instance = qmf::Data(_package.data_Sysconfig); + + _instance.setProperty("hostname", mh_hostname()); + _instance.setProperty("uuid", mh_uuid()); + _instance.setProperty("is_postboot_configured", 0); + + _agent_session.addData(_instance, "sysconfig"); + return 0; +} + +static void +set_configured() { + if(!g_file_test(configured_fn, G_FILE_TEST_EXISTS)) { + g_creat(configured_fn, S_IRWXU); + } +} + +static int +is_configured(uint32_t flags) { + + if(flags & MH_SYSCONFIG_FLAG_FORCE) { + return 0; + } + + if(g_file_test(configured_fn, G_FILE_TEST_EXISTS)) { + return 1; + } + return 0; +} + +gboolean +ConfigAgent::invoke(qmf::AgentSession session, qmf::AgentEvent event, gpointer user_data) +{ + int rc = 0; + uint32_t flags; + + const std::string& methodName(event.getMethodName()); + if (event.getType() != qmf::AGENT_METHOD) { + return TRUE; + } + + qpid::types::Variant::Map& args = event.getArguments(); + + if (methodName == "run_uri") { + flags = args["flags"].asUint32(); + if((is_configured(flags)) == 0) { + rc = mh_sysconfig_run_uri(args["uri"].asString().c_str(), + flags, + args["scheme"].asString().c_str()); + if (rc == 0) { + set_configured(); + } + } + event.addReturnArgument("configured", rc); + } else if (methodName == "run_string") { + flags = args["flags"].asUint32(); + if((is_configured(flags)) == 0) { + rc = mh_sysconfig_run_string(args["data"].asString().c_str(), + flags, + args["scheme"].asString().c_str()); + if (rc == 0) { + set_configured(); + } + } + event.addReturnArgument("configured", rc); + } else if (methodName == "query") { + flags = args["flags"].asUint32(); + const char *data = NULL; + if((is_configured(flags)) == 0) { + data = mh_sysconfig_query(args["query"].asString().c_str(), + flags, + args["scheme"].asString().c_str()); + } + event.addReturnArgument("Query", data); + } else if (methodName == "is_configured") { + rc = is_configured(0); + _instance.setProperty("is_postboot_configured", rc); + event.addReturnArgument("configured", rc); + } else { + session.raiseException(event, MH_NOT_IMPLEMENTED); + goto bail; + } + + session.methodSuccess(event); + +bail: + return TRUE; +} diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 6db157c..8fe81f2 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -5,13 +5,13 @@ if(CXXTEST_FOUND) ENABLE_TESTING() CXXTEST_ADD_TEST(mh_api_network_unittest network_unittest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mh_api_network.h) CXXTEST_ADD_TEST(mh_api_host_unittest host_unittest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mh_api_host.h) - CXXTEST_ADD_TEST(mh_api_postboot_unittest postboot_unittest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mh_api_postboot.h) + CXXTEST_ADD_TEST(mh_api_sysconfig_unittest sysconfig_unittest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mh_api_sysconfig.h) CXXTEST_ADD_TEST(mh_hsa_unittest hsa_unittest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mh_hsa_${VARIANT}.h) add_library(mh_tester SHARED test_utilities.c) - target_link_libraries(mh_tester ${pcre_LIBRARIES} mcommon mnetwork mhost mpostboot) + target_link_libraries(mh_tester ${pcre_LIBRARIES} mcommon mnetwork mhost msysconfig) target_link_libraries(mh_api_network_unittest mh_tester) target_link_libraries(mh_api_host_unittest mh_tester) - target_link_libraries(mh_api_postboot_unittest mh_tester) + target_link_libraries(mh_api_sysconfig_unittest mh_tester) target_link_libraries(mh_hsa_unittest mh_tester) endif(CXXTEST_FOUND)
diff --git a/src/tests/mh_api_sysconfig.h b/src/tests/mh_api_sysconfig.h new file mode 100644 index 0000000..a9a3ebc --- /dev/null +++ b/src/tests/mh_api_sysconfig.h @@ -0,0 +1,34 @@ +#ifndef __MH_API_NETWORK_UNITTEST_H +#define __MH_API_NETWORK_UNITTEST_H +#include <iostream> +#include <string> +#include <sstream> +#include <utility> +#include <vector> +#include <cstdlib> +#include <cstdio> +#include <sys/stat.h> +#include <dirent.h> +#include <cxxtest/TestSuite.h> + +extern "C" { +#include "matahari/sysconfig.h" +#include <glib.h> +#include "mh_test_utilities.h" +}; + +using namespace std; + +class MhApiSysconfigSuite : public CxxTest::TestSuite +{ + public: + + void testIsConfigured(void) + { + const char *uri = "http://matahariproject.org/atom.xml"; + uint32_t flags = 0; + TS_ASSERT((mh_sysconfig_run_uri(uri, flags, "puppet")) != -1); + } +}; + +#endif