[Saga-devel] saga SVN commit 3343: /trunk/adaptors/ssh/
amerzky at cct.lsu.edu
amerzky at cct.lsu.edu
Wed Jan 21 16:06:13 CST 2009
User: amerzky
Date: 2009/01/21 04:06 PM
Modified:
/trunk/adaptors/ssh/ssh_context/
ssh_context_adaptor.cpp
/trunk/adaptors/ssh/ssh_job/
ssh_job.cpp, ssh_job.hpp, ssh_job_service.cpp, ssh_job_service.hpp
Log:
allow forwarding of ssh keys. In some sense, this is like proxy
delegation, only that keys don't expire. So, please be careful!
A
File Changes:
Directory: /trunk/adaptors/ssh/ssh_context/
===========================================
File [modified]: ssh_context_adaptor.cpp
Delta lines: +61 -11
===================================================================
--- trunk/adaptors/ssh/ssh_context/ssh_context_adaptor.cpp 2009-01-21 17:19:30 UTC (rev 3342)
+++ trunk/adaptors/ssh/ssh_context/ssh_context_adaptor.cpp 2009-01-21 22:05:50 UTC (rev 3343)
@@ -134,7 +134,6 @@
std::pair <std::string, std::string> entry (saga::attributes::context_type,
"ssh");
-
entries.push_back (entry);
s->add_proto_context (entries);
@@ -151,16 +150,51 @@
//
// init a cert, either from a given path, or from a default location
//
-context_cpi_impl::cert_info_t context_cpi_impl::get_cert_info (std::string path)
+context_cpi_impl::cert_info_t context_cpi_impl::get_cert_info (std::string key_path)
{
+ std::string key_path_pub;
+ std::string key_user;
+
cert_info_t ci;
- ci.success = true;
+ ci.success = true;
+ ci.private_key = key_path;
- // fall back to default if needed
- if ( path == "" )
+
+ // tr to find fallbacks
+ if ( ci.private_key == "" )
{
+ // if SAGA_SSH_KEY is set in the environment, we use that as default
+ const char * saga_ssh_key = ::getenv ("SAGA_SSH_KEY");
+
+ if ( NULL != saga_ssh_key )
+ {
+ ci.private_key = saga_ssh_key;
+
+ // is the public key location also given?
+ const char * saga_ssh_pub = ::getenv ("SAGA_SSH_PUB");
+
+ if ( NULL != saga_ssh_pub )
+ {
+ key_path_pub = saga_ssh_pub;
+ }
+
+ // is the public key location also given?
+ const char * saga_ssh_user = ::getenv ("SAGA_SSH_USER");
+
+ if ( NULL != saga_ssh_user )
+ {
+ key_user = saga_ssh_user;
+ }
+ }
+ }
+
+
+ // anther fallback is ~/.{ssh,ssh2}/id_[dr]sa
+ if ( ci.private_key == "" )
+ {
const char * home = ::getenv ("HOME");
+
if ( home == NULL )
{
ci.errormessage = "Cannot determine home directory, i.e. default ssh key location";
@@ -192,13 +226,13 @@
if ( d.exists ("id_dsa") &&
d.is_file ("id_dsa") )
{
- path = d.get_url ().get_path () + "/id_dsa";
+ ci.private_key = d.get_url ().get_path () + "/id_dsa";
}
else
if ( d.exists ("id_rsa") &&
d.is_file ("id_rsa") )
{
- path = d.get_url ().get_path () + "/id_rsa";
+ ci.private_key = d.get_url ().get_path () + "/id_rsa";
}
else
{
@@ -210,14 +244,30 @@
+
+ // default for public key
+ if ( key_path_pub == "" )
+ {
+ ci.public_key = key_path + ".pub";
+ }
+
+ ci.public_key = key_path_pub;
+
+
+ // default for key_user
+ if ( key_user == "" )
+ {
+ key_user = ::getpwuid (::getuid ())->pw_name;
+ }
+
+ ci.userid = key_user;
+
+
+
// check if given private key, and related public-key, exist
// FIXME: use saga::filesystem!
struct stat buf;
- ci.private_key = path;
- ci.public_key = path + ".pub";
- ci.userid = ::getpwuid (::getuid ())->pw_name;
-
if ( 0 != ::stat (ci.private_key.c_str (), &buf) )
{
ci.errormessage = "Cannot access private ssh key";
Directory: /trunk/adaptors/ssh/ssh_job/
=======================================
File [modified]: ssh_job.cpp
Delta lines: +15 -0
===================================================================
--- trunk/adaptors/ssh/ssh_job/ssh_job.cpp 2009-01-21 17:19:30 UTC (rev 3342)
+++ trunk/adaptors/ssh/ssh_job/ssh_job.cpp 2009-01-21 22:05:50 UTC (rev 3343)
@@ -169,6 +169,21 @@
new_args.push_back (key_);
new_args.push_back (user_ + "@" + host_);
+ // add environment as ssh, via /usr/bin/env
+ if ( old_jd_.attribute_exists (saga::job::attributes::description_environment) )
+ {
+ std::vector <std::string> env = old_jd_.get_vector_attribute
+ (saga::job::attributes::description_environment);
+
+ new_args.push_back ("/usr/bin/env");
+
+ for ( unsigned int i = 0; i < env.size (); i++ )
+ {
+ new_args.push_back (env[i]);
+ }
+ }
+
+
// readd old exe and args
new_args.push_back (old_exe);
File [modified]: ssh_job.hpp
Delta lines: +0 -1
===================================================================
--- trunk/adaptors/ssh/ssh_job/ssh_job.hpp 2009-01-21 17:19:30 UTC (rev 3342)
+++ trunk/adaptors/ssh/ssh_job/ssh_job.hpp 2009-01-21 22:05:50 UTC (rev 3343)
@@ -59,7 +59,6 @@
std::vector <std::string> scp_opt_;
std::map <std::string, std::string> ini_;
- std::map <std::string, std::string> env_;
saga::job::job j_; // forward to default job
File [modified]: ssh_job_service.cpp
Delta lines: +171 -30
===================================================================
--- trunk/adaptors/ssh/ssh_job/ssh_job_service.cpp 2009-01-21 17:19:30 UTC (rev 3342)
+++ trunk/adaptors/ssh/ssh_job/ssh_job_service.cpp 2009-01-21 22:05:50 UTC (rev 3343)
@@ -7,9 +7,13 @@
// system includes
#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
// stl includes
#include <vector>
+#include <fstream>
// saga includes
#include <saga/saga.hpp>
@@ -46,6 +50,12 @@
adaptor_data adata (this);
instance_data idata (this);
+ // create local job service which handles all job submissions. This
+ // may throw.
+ js_ = TR1::shared_ptr <saga::job::service> (new saga::job::service ("fork://localhost"));
+
+
+
ini_ = adap_ini.get_section ("preferences").get_entries ();
rm_ = idata->rm_;
@@ -81,7 +91,6 @@
if ( contexts[i].attribute_exists ("Type") &&
contexts[i].get_attribute ("Type") == "ssh" )
{
- SAGA_LOG_ALWAYS ("Using this context");
ssh_contexts.push_back (contexts[i]);
}
}
@@ -109,6 +118,8 @@
// pick up that identity
//
// FIXME: we need to be able to create multiple default ssh contexts
+
+
for ( int j = 0; j < ssh_contexts.size (); j++ )
{
@@ -119,13 +130,15 @@
// FIXME: check if attribs exist
- if ( ! ctx_.attribute_exists ("UserKey") )
+ if ( ! ctx_.attribute_exists ("UserKey") ||
+ ! ctx_.attribute_exists ("UserCert") )
{
// _need_ key to be useful
break;
}
- key_ = ctx_.get_attribute ("UserKey");
+ loc_ssh_key_priv_ = ctx_.get_attribute ("UserKey");
+ loc_ssh_key_pub_ = ctx_.get_attribute ("UserCert");
if ( ctx_.attribute_exists ("UserKey") )
@@ -150,25 +163,136 @@
}
+ // determine some additional vars used for the envoronement of started
+ // jobs
+ // FIXME: the saga jobid leads to invalid command lines and file
+ // names
+ // try
+ // {
+ // saga::job::job self = js_->get_self ();
+ // parent_id_ = self.get_job_id ();
+ // }
+ // catch ( ... )
+ {
+ // did not get jobid - invent one
+ std::stringstream ss;
+ ss << "saga-parent-id" << ::getpid ();
+ parent_id_ = ss.str ();
+ }
+
+ rem_ssh_key_pub_ = std::string ("/tmp/saga_") + parent_id_ + "_ssh";
+ rem_ssh_key_priv_ = std::string ("/tmp/saga_") + parent_id_ + "_ssh.pub";
+
+ env_.push_back (std::string ("SAGA_PARENT_JOBID") + "=" + parent_id_);
+ env_.push_back (std::string ("SAGA_SSH_KEY") + "=" + rem_ssh_key_pub_);
+ env_.push_back (std::string ("SAGA_SSH_PUB") + "=" + rem_ssh_key_priv_);
+ env_.push_back (std::string ("SAGA_SSH_USER") + "=" + user_);
+
+
+ // prepare the remote host
saga::adaptors::utils::process proc;
- if ( ini_["distribute_idendity"] == "yes" ||
- ini_["distribute_idendity"] == "true" )
+ if ( ini_["distribute_identity"] == "yes" ||
+ ini_["distribute_identity"] == "true" )
{
- SAGA_LOG_DEBUG (" copying identity file");
+ {
+ SAGA_LOG_DEBUG (" copying private key");
- proc.set_cmd (scp_bin_);
- proc.set_args (scp_opt_);
+ proc.set_cmd (scp_bin_);
+ proc.set_args (scp_opt_);
- // FIXME: ensure that context is complete
- proc.add_args ("-i", key_);
+ // first copy private key
+ // FIXME: ensure that context is complete
+ proc.add_args ("-i", loc_ssh_key_priv_);
- // file to stage
- // FIXME: ensure that context is complete
- // FIXME: we silently assume that the .ssh dirctory exists
- // FIXME: the target below SHOULD not exist *aehem*
- proc.add_arg (key_);
- proc.add_arg (user_ + "@" + host_ + ":.ssh/id_saga");
+ // file to stage
+ // FIXME: ensure that context is complete
+ // FIXME: we silently assume that the .ssh dirctory exists
+ // FIXME: the target below SHOULD not exist *aehem*
+ proc.add_arg (loc_ssh_key_priv_);
+ proc.add_arg (user_ + "@" + host_ + ":" + rem_ssh_key_priv_);
+
+ (void) proc.run_sync ();
+
+ if ( ! proc.done () )
+ {
+ SAGA_ADAPTOR_THROW ("Could not copy private key", saga::NoSuccess);
+ }
+ }
+
+ {
+ SAGA_LOG_DEBUG (" copying public key");
+
+ // if ok, copy public key
+ proc.set_args (scp_opt_);
+
+ // FIXME: ensure that context is complete
+ proc.add_args ("-i", loc_ssh_key_priv_);
+
+ // file to stage
+ // FIXME: ensure that context is complete
+ // FIXME: we silently assume that the .ssh dirctory exists
+ // FIXME: the target below SHOULD not exist *aehem*
+ proc.add_arg (loc_ssh_key_pub_);
+ proc.add_arg (user_ + "@" + host_ + ":" + rem_ssh_key_pub_);
+
+ (void) proc.run_sync ();
+
+ if ( ! proc.done () )
+ {
+ SAGA_ADAPTOR_THROW ("Could not copy public key", saga::NoSuccess);
+ }
+ }
+
+ {
+ SAGA_LOG_DEBUG (" register public key");
+ // FIXME: need to append public key to local authorized_keys
+ // file, so that application can call back home. A key is
+ // exactly one line: so we append the key, and then do
+ // a sort|uniq on the authorized_keys file, to avoid
+ // duplicates.
+
+ char* home_tmp = ::getenv ("HOME");
+
+ if ( home_tmp == NULL )
+ {
+ SAGA_ADAPTOR_THROW ("Could not determine home directory", saga::NoSuccess);
+ }
+
+ std::string home = home_tmp;
+
+
+ // FIXME: use better name
+ std::fstream cmd;
+ cmd.open ("/tmp/saga_tmp_cmd", std::fstream::out);
+
+ cmd << " cat " << loc_ssh_key_pub_
+ << " " << home << "/.ssh/authorized_keys"
+ << " | sort | uniq > /tmp/saga_keys_tmp"
+ << std::endl
+ << " mv /tmp/saga_keys_tmp "
+ << home << "/.ssh/authorized_keys"
+ << std::endl;
+
+ cmd.close();
+
+ ::chmod ("/tmp/saga_tmp_cmd", S_IRWXU);
+
+ proc.set_cmd ("/bin/sh");
+ proc.clear_args ();
+ proc.add_args ("-c", "/tmp/saga_tmp_cmd");
+
+ (void) proc.run_sync ();
+
+ if ( ! proc.done () )
+ {
+ SAGA_ADAPTOR_THROW ("Could not register public key", saga::NoSuccess);
+ }
+
+ // remove temporary script
+ ::unlink ("/tmp/saga_tmp_cmd");
+
+ }
}
else
{
@@ -178,28 +302,25 @@
proc.set_args (ssh_opt_);
// FIXME: ensure that context is complete
- proc.add_args ("-i", key_);
+ proc.add_args ("-i", loc_ssh_key_priv_);
proc.add_arg ( user_ + "@" + host_);
proc.add_arg ("true");
- }
+ (void) proc.run_sync ();
- (void) proc.run_sync ();
+ if ( ! proc.done () )
+ {
+ SAGA_ADAPTOR_THROW ("Could not run a test ssh command", saga::NoSuccess);
+ }
+ }
- if ( proc.done () )
- {
- // remember key location, so we can tell the started jobs about it
- env_["SAGA_ADAPTOR_SSH_KEY"] = ".ssh/id_saga";
- // create local job service which handles all job submissions
- js_ = TR1::shared_ptr <saga::job::service> (new saga::job::service ("fork://localhost"));
-
- // we are done
- return;
- }
+ // we are done - no exception 'til now!
+ return;
}
- // no context was ok for scp or ssh - flag error
+ // no context was ok for scp or ssh, or preparation failed - flag error
+ // FIXME: throw above when error occurs, with better error message
SAGA_ADAPTOR_THROW ("Could not connect to remote host", saga::NoSuccess);
}
@@ -220,6 +341,26 @@
saga::session s;
s.add_context (ctx_);
+ // the ssh job adaptor sets a couple of env variables:
+ // SAGA_PARENT_JOBID: saga job id of self, i.e. the spawning process
+ // SAGA_SSH_KEY: location of private ssh key used to spawn process
+ // SAGA_SSH_PUB: location of public ssh key used to spawn process
+ // SAGA_SSH_USER: user which spawned the process
+ std::vector <std::string> new_env;
+ if ( jd.attribute_exists (saga::job::attributes::description_environment) )
+ {
+ new_env = jd.get_vector_attribute (saga::job::attributes::description_environment);
+ }
+
+ for ( int i = 0; i < env_.size (); i++ )
+ {
+ new_env.push_back (env_[i]);
+ SAGA_LOG_ALWAYS(env_[i].c_str ());
+ }
+
+ jd.set_vector_attribute (saga::job::attributes::description_environment, new_env);
+
+ // create the job with the 'fixed' job description
saga::job::job job = saga::adaptors::job (rm_, jd, s);
ret = job;
}
File [modified]: ssh_job_service.hpp
Delta lines: +7 -1
===================================================================
--- trunk/adaptors/ssh/ssh_job/ssh_job_service.hpp 2009-01-21 17:19:30 UTC (rev 3342)
+++ trunk/adaptors/ssh/ssh_job/ssh_job_service.hpp 2009-01-21 22:05:50 UTC (rev 3343)
@@ -59,11 +59,17 @@
std::string ssh_bin_;
std::string scp_bin_;
+ std::string parent_id_; // id of self
+ std::string loc_ssh_key_pub_; // local ssh key
+ std::string loc_ssh_key_priv_; // local ssh key
+ std::string rem_ssh_key_pub_; // deployed ssh key
+ std::string rem_ssh_key_priv_; // deployed ssh key
+
std::vector <std::string> ssh_opt_;
std::vector <std::string> scp_opt_;
std::map <std::string, std::string> ini_;
- std::map <std::string, std::string> env_;
+ std::vector <std::string> env_;
void dump_context (saga::context c);
More information about the saga-devel
mailing list