This patch makes the classad plugin use the REST API. This introduces a requirement on librest so you will now have to have rest-devel, glib2-devel, libsoup-devel, and libxml2-devel installed to build.
Signed-off-by: Ian Main imain@redhat.com --- configure.ac | 6 + deltacloud-aggregator.spec.in | 8 ++ src/app/util/condormatic.rb | 11 +- src/classad_plugin/Makefile.am | 12 +- src/classad_plugin/classad_plugin.rb | 79 ------------- src/classad_plugin/deltacloud_classad_plugin.cpp | 128 +++++++++++---------- 6 files changed, 92 insertions(+), 152 deletions(-) delete mode 100644 src/classad_plugin/classad_plugin.rb
diff --git a/configure.ac b/configure.ac index 9598925..c597a74 100644 --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,12 @@ elif test "x$with_classads" = "x"; then fi fi
+PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.18) +PKG_CHECK_MODULES(SOUP, libsoup-2.4) +PKG_CHECK_MODULES(XML, libxml-2.0) +PKG_CHECK_MODULES(GTHREAD, gthread-2.0) +PKG_CHECK_MODULES(REST, rest-0.6) + # If using gcc and default CFLAGS, enable some warnings. test x"$ac_ct_CC:$CFLAGS" = 'xgcc:-g -O2' \ && CFLAGS="$CFLAGS -Wshadow -Wall -Werror" diff --git a/deltacloud-aggregator.spec.in b/deltacloud-aggregator.spec.in index 0632f79..c7d6a7b 100644 --- a/deltacloud-aggregator.spec.in +++ b/deltacloud-aggregator.spec.in @@ -38,6 +38,10 @@ Requires: postgresql-server Requires: ruby-postgres Requires: ruby-RMagick Requires: classads >= 1.0 +Requires: libsoup >= 2.0 +Requires: glib2 >= 2.0 +Requires: libxml2 >= 2.6 +Requires: rest >= 0.6 Requires: condor >= 7.5.5-10dcloud Requires: iwhd Requires: deltacloud-configure @@ -45,6 +49,10 @@ Requires: deltacloud-configure BuildRequires: ruby BuildRequires: ruby-devel BuildRequires: classads-devel >= 1.0 +BuildRequires: libsoup-devel >= 2.0 +BuildRequires: glib2-devel >= 2.0 +BuildRequires: libxml2-devel >= 2.6 +BuildRequires: rest-devel >= 0.6
%package daemons Summary: Deltacloud Aggregator daemons config diff --git a/src/app/util/condormatic.rb b/src/app/util/condormatic.rb index 8b4e224..1d52d21 100644 --- a/src/app/util/condormatic.rb +++ b/src/app/util/condormatic.rb @@ -57,13 +57,10 @@ def condormatic_instance_create(task)
requirements = "requirements = hardwareprofile == "#{instance.hardware_profile.id}" && image == "#{instance.template.id}"" requirements += " && realm == "#{realm.id}"" if realm != nil - # We may need to add some stuff to the provider classads like pool id, provider id etc. This is mostly just - # to test and make sure this works for now. - # - # This is currently broken as the condor plugin loads models without initializing rails. - # However, recent changes have required that rails be initialized in order to load the - # pool and quota models. - #requirements += " && deltacloud_quota_check("#{job_name}", other.cloud_account_id)" + # Call into the deltacloud quota plugin. This uses a REST API to call back into the + # conductor to check quotas as the last thing in the logical AND to match a provider + # account. + requirements += " && deltacloud_quota_check(#{instance.id}, other.cloud_account_id)" requirements += "\n"
pipe.puts requirements diff --git a/src/classad_plugin/Makefile.am b/src/classad_plugin/Makefile.am index 9334f5f..5d40240 100644 --- a/src/classad_plugin/Makefile.am +++ b/src/classad_plugin/Makefile.am @@ -1,12 +1,14 @@ -AM_CPPFLAGS=-I`ruby -e "require 'rbconfig' ; puts Config::CONFIG['archdir']"` \ - -DDELTACLOUD_INSTALL_DIR="$(DELTACLOUD_INSTALL_DIR)" -DLOGFILE="/var/log/condor/deltacloud_condor_plugin.log" +AM_CPPFLAGS= $(GLIB_CFLAGS) $(GTHREAD_CFLAGS) \ + $(SOUP_CFLAGS) $(SOUP_GNOME_CFLAGS) \ + $(XML_CFLAGS) $(REST_CFLAGS) \ + -DLOGFILE="/var/log/condor/deltacloud_condor_plugin.log"
classadplugindir=$(pkgdatadir)/classad_plugin
classadplugin_LTLIBRARIES = deltacloud_classad_plugin.la
deltacloud_classad_plugin_la_SOURCES = deltacloud_classad_plugin.cpp -deltacloud_classad_plugin_la_LIBADD = -lclassad -lruby +deltacloud_classad_plugin_la_LIBADD = $(GLIB_LIBS) $(GTHREAD_LIBS) \ + $(SOUP_LIBS) $(SOUP_GNOME_LIBS) $(XML_LIBS) $(REST_LIBS)\ + -lclassad deltacloud_classad_plugin_la_LDFLAGS = -module -avoid-version -shared - -classadplugin_DATA = classad_plugin.rb diff --git a/src/classad_plugin/classad_plugin.rb b/src/classad_plugin/classad_plugin.rb deleted file mode 100644 index 2aabfb9..0000000 --- a/src/classad_plugin/classad_plugin.rb +++ /dev/null @@ -1,79 +0,0 @@ -require 'rubygems' -require 'active_record' -require 'search_filter' -require 'permissioned_object' -require 'authlogic' -require 'user' -require 'instance' -require 'cloud_account' -require 'pool' -require 'quota' - -class BashParser - def initialize(filename) - @config = {} - - f = File.open(filename, 'r') - while (line = f.gets) - strip = line.strip.gsub(/#.*/, '').gsub(/^export /, '') - if strip.length == 0 - next - end - - x = strip.split('=') - if x.length != 2 - next - end - - @config[x[0]] = x[1] - end - - f.close - end - - def get_value(name) - @config[name] - end -end - -def classad_plugin(logf, conf_path, instance_key, account_id) - rails_env = "development" - - begin - config = BashParser.new('/etc/sysconfig/deltacloud-rails') - env = config.get_value('RAILS_ENV') - if not env.nil? - rails_env = env - end - rescue - # if any of this failed, then just assume the development database and - # hope for the best - end - - logf.puts "loading db config from #{conf_path}, using environment #{rails_env}" - conf = YAML::load(File.open(conf_path)) - ActiveRecord::Base.establish_connection(conf[rails_env]) - - # I left the puts in here because you can run condor_negotiator -f from the - # command line and it will print this stuff out. Very nice for debugging. - logf.puts "getting instance from key #{instance_key}" - instance = Instance.find(:first, - :conditions => [ "condor_job_id = ?", instance_key ]) - logf.puts "getting cloud account from id #{account_id}" - cloud_account = CloudAccount.find(:first, - :conditions => [ "id = ?", account_id ]) - - logf.puts "instance is: #{instance}, cloud account is #{cloud_account}" - - return false if instance.nil? - return false if cloud_account.nil? - - logf.puts "checking quota.." - ret = Quota.can_start_instance?(instance, cloud_account) - logf.puts "After checking quota, ret is #{ret}" - - logf.puts "Disconnecting from the database" - ActiveRecord::Base.connection.disconnect! - - return ret -end diff --git a/src/classad_plugin/deltacloud_classad_plugin.cpp b/src/classad_plugin/deltacloud_classad_plugin.cpp index 74d6023..cfd52c8 100644 --- a/src/classad_plugin/deltacloud_classad_plugin.cpp +++ b/src/classad_plugin/deltacloud_classad_plugin.cpp @@ -1,4 +1,3 @@ -#include <ruby.h> #include <stdio.h>
#include <iostream> @@ -7,6 +6,9 @@ #include "classad/classad_distribution.h" #include "classad/fnCall.h"
+#include <rest/rest-proxy.h> +#include <rest/rest-xml-parser.h> + using namespace std; #ifdef WANT_CLASSAD_NAMESPACE using namespace classad; @@ -70,6 +72,26 @@ static void _print_value(FILE *fp, Value val, const char *name) fprintf(fp, "%s\n", sstr.str().c_str()); }
+static RestXmlNode * +get_xml (RestProxyCall *call) +{ + RestXmlParser *parser; + RestXmlNode *root; + GError *error = NULL; + + parser = rest_xml_parser_new (); + + root = rest_xml_parser_parse_from_data (parser, + rest_proxy_call_get_payload (call), + rest_proxy_call_get_payload_length (call)); + + g_object_unref (call); + g_object_unref (parser); + + return root; +} + + /* * Perform our quota check against the deltacloud aggregator database. * This function expects: @@ -87,14 +109,18 @@ bool deltacloud_quota_check(const char *name, const ArgumentList &arglist, EvalState &state, Value &result) { - Value instance_key; + Value instance_id; Value account_id; FILE *fp; - VALUE res; bool val = false; - char *ruby_string; - std::stringstream method_args; - int rc; + RestProxy *proxy; + RestProxyCall *call; + RestXmlNode *root; + std::stringstream rest_call; + GError *err = NULL; + + g_thread_init (NULL); + g_type_init ();
result.SetBooleanValue(false);
@@ -106,22 +132,22 @@ deltacloud_quota_check(const char *name, const ArgumentList &arglist, goto do_ret; }
- if (!arglist[0]->Evaluate(state, instance_key)) { + if (!arglist[0]->Evaluate(state, instance_id)) { result.SetErrorValue(); - fprintf(fp, "Could not evaluate argument 0 to instance key\n"); + fprintf(fp, "Could not evaluate argument 0 to instance id\n"); goto do_ret; } if (!arglist[1]->Evaluate(state, account_id)) { result.SetErrorValue(); - fprintf(fp, "Could not evaluate argument 1 to account_id\n"); + fprintf(fp, "Could not evaluate argument 1 to account id\n"); goto do_ret; }
- print_type(fp, instance_key); - print_value(fp, instance_key); - if (instance_key.GetType() != Value::STRING_VALUE) { + print_type(fp, instance_id); + print_value(fp, instance_id); + if (instance_id.GetType() != Value::INTEGER_VALUE) { result.SetErrorValue(); - fprintf(fp, "Instance type was not a string\n"); + fprintf(fp, "Instance id type was not an integer\n"); goto do_ret; }
@@ -133,56 +159,36 @@ deltacloud_quota_check(const char *name, const ArgumentList &arglist, goto do_ret; }
- ruby_init(); - ruby_init_loadpath(); - - method_args << "'" << DELTACLOUD_INSTALL_DIR << "/config/database.yml', '" - << instance_key << "', " << account_id; - - rc = asprintf(&ruby_string, - "$: << '%s/classad_plugin'\n" - "$: << '%s/app/models'\n" - "logf = File.new('%s', 'a')\n" - "logf.puts "Loading ruby support file from %s/classad_plugin"\n" - "begin\n" - " require 'classad_plugin.rb'\n" - " ret = classad_plugin(logf, %s)\n" - "rescue Exception => ex\n" - " logf.puts "Error running classad plugin: #{ex.message}"\n" - " logf.puts ex.backtrace\n" - " ret = false\n" - "end\n" - "logf.close\n" - "ret", - DELTACLOUD_INSTALL_DIR, - DELTACLOUD_INSTALL_DIR, - LOGFILE, - DELTACLOUD_INSTALL_DIR, - method_args.str().c_str()); - - if (rc < 0) { - fprintf(fp, "Failed to allocate memory for asprintf\n"); - goto do_ret; + rest_call << "resources/instances/" << instance_id << "/can_start/" << account_id; + + // Call rest API to get answer on quota.. + proxy = rest_proxy_new ("http://localhost:3000/deltacloud", FALSE); + call = rest_proxy_new_call (proxy); + rest_proxy_call_set_function (call, rest_call.str().c_str()); + + fprintf(fp, "Calling REST API with %s\n", rest_call.str().c_str()); + rest_proxy_call_sync (call, &err); + + if (err != NULL) { + fprintf (fp, "Error calling REST API: %s\n", err->message); + } else { + root = get_xml (call); + if (root) { + RestXmlNode *node; + gchar *value; + + node = rest_xml_node_find (root, "value"); + value = node->content; + + fprintf (fp, "return value is %s\n", value); + if (strncmp(value, "true", 4) == 0) { + result.SetBooleanValue(true); + val = true; + } + } }
- fprintf(fp, "ruby string is %s\n", ruby_string); - fflush(fp); - - res = rb_eval_string(ruby_string); - free(ruby_string); - - /* FIXME: I'd like to call ruby_finalize here, but it spews weird errors: - * - * Error running classad plugin: wrong argument type Mutex (expected Data) - */ - //ruby_finalize(); - - fprintf(fp, "Returned result from ruby code was %s\n", (res == Qtrue) ? "true" : "false"); - - if (res == Qtrue) { - result.SetBooleanValue(true); - val = true; - } + g_object_unref (proxy);
do_ret: fclose(fp);
aeolus-devel@lists.fedorahosted.org