mobilize-ssh 1.0.7 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -83,8 +83,16 @@ fails in mid-copy. By default this is tmp/file/.
83
83
  * nodes, identified by aliases, such as `test_node`. This alias is what you should
84
84
  pass into the "node" param over in the ssh.run task.
85
85
 
86
- Each node has a host, and optionally has a gateway. If you don't need a
87
- gateway, remove that row from the configuration file.
86
+ Each node has:
87
+ * a host;
88
+ * a gateway (optional); If you don't need a gateway, remove that row from the configuration file.
89
+ * sudoers; these are user names that are allowed to pass su_user params
90
+ to the run call. This requires passwordless sudo for the host user.
91
+ * su_all_users true/false option, which ensures that commands are executed by the
92
+ user on the Runner. It prefixes all commands with sudo su <user_name> before executing the
93
+ command. This is strongly recommended if possible as it ensures users do
94
+ not overstep their permissions. This requires passwordless sudo for the
95
+ host user and accounts on the host machine for each user.
88
96
 
89
97
  Each host and gateway has a series of ssh params:
90
98
  * name - the ip address or name of the host
@@ -16,6 +16,14 @@ module Mobilize
16
16
  Ssh.config['nodes'][node]['gateway']
17
17
  end
18
18
 
19
+ def Ssh.sudoers(node)
20
+ Ssh.config['nodes'][node]['sudoers']
21
+ end
22
+
23
+ def Ssh.su_all_users(node)
24
+ Ssh.config['nodes'][node]['su_all_users']
25
+ end
26
+
19
27
  #determine if current machine is on host domain, needs gateway if one is provided and it is not
20
28
  def Ssh.needs_gateway?(node)
21
29
  host_domain_name = Ssh.host(node)['name'].split(".")[-2..-1].join(".")
@@ -34,9 +42,17 @@ module Mobilize
34
42
  return true if file_hash.keys.length>0
35
43
  end
36
44
 
45
+ def Ssh.set_key_permissions(key_path)
46
+ #makes sure permissions are set as appropriate for ssh key
47
+ "chmod a-rwx #{key_path}".bash
48
+ "chmod u+rw #{key_path}".bash
49
+ return true
50
+ end
51
+
37
52
  def Ssh.scp(node,from_path,to_path)
38
53
  name,key,port,user = Ssh.host(node).ie{|h| ['name','key','port','user'].map{|k| h[k]}}
39
54
  key_path = "#{Base.root}/#{key}"
55
+ Ssh.set_key_permissions(key_path)
40
56
  opts = {:port=>(port || 22),:keys=>key_path}
41
57
  if Ssh.needs_gateway?(node)
42
58
  gname,gkey,gport,guser = Ssh.gateway(node).ie{|h| ['name','key','port','user'].map{|k| h[k]}}
@@ -52,9 +68,9 @@ module Mobilize
52
68
  end
53
69
 
54
70
  def Ssh.run(node,command,file_hash=nil,su_user=nil)
55
- name,key,port,user = Ssh.host(node).ie{|h| ['name','key','port','user'].map{|k| h[k]}}
71
+ key,user = Ssh.host(node).ie{|h| ['key','user'].map{|k| h[k]}}
56
72
  key_path = "#{Base.root}/#{key}"
57
- opts = {:port=>(port || 22),:keys=>key_path}
73
+ Ssh.set_key_permissions(key_path)
58
74
  su_user ||= user
59
75
  file_hash ||= {}
60
76
  #make sure the dir for this command is clear
@@ -64,48 +80,55 @@ module Mobilize
64
80
  Ssh.pop_comm_dir(comm_dir,file_hash)
65
81
  #move any files up to the node
66
82
  rem_dir = nil
83
+ #make sure user starts in rem_dir
84
+ rem_dir = "#{comm_md5}/"
85
+ #make sure the rem_dir is gone
86
+ Ssh.fire!(node,"rm -rf #{rem_dir}")
67
87
  if File.exists?(comm_dir)
68
- #make sure user starts in rem_dir
69
- rem_dir = "#{comm_md5}/"
70
- command = ["cd #{rem_dir}",command].join(";")
71
- #make sure the rem_dir is gone
72
- Ssh.run(node,"rm -rf #{rem_dir}")
73
88
  Ssh.scp(node,comm_dir,rem_dir)
74
89
  "rm -rf #{comm_dir}".bash
75
- if su_user
76
- chown_command = "sudo chown -R #{su_user} #{rem_dir}"
77
- Ssh.run(node,chown_command)
78
- end
79
- end
80
- if su_user != user
81
- #wrap the command in sudo su -c
82
- command = %{sudo su #{su_user} -c "#{command}"}
90
+ else
91
+ #create folder
92
+ mkdir_command = "mkdir #{rem_dir}"
93
+ Ssh.fire!(node,mkdir_command)
83
94
  end
84
- result = nil
85
- #one with gateway, one without
95
+ #create cmd_file in rem_folder
96
+ cmd_file = "#{comm_md5}.sh"
97
+ cmd_path = "#{rem_dir}#{cmd_file}"
98
+ Ssh.write(node,command,cmd_path)
99
+ full_cmd = "(cd #{rem_dir} && sh #{cmd_file})"
100
+ #fire_cmd runs sh on cmd_path, optionally with sudo su
101
+ fire_cmd = if su_user != user
102
+ %{sudo su #{su_user} -c "#{full_cmd}"}
103
+ else
104
+ full_cmd
105
+ end
106
+ result = Ssh.fire!(node,fire_cmd)
107
+ #remove the directory after you're done
108
+ rm_cmd = "rm -rf #{rem_dir}"
109
+ Ssh.fire!(node,rm_cmd)
110
+ result
111
+ end
112
+
113
+ def Ssh.fire!(node,cmd)
114
+ name,key,port,user = Ssh.host(node).ie{|h| ['name','key','port','user'].map{|k| h[k]}}
115
+ key_path = "#{Base.root}/#{key}"
116
+ Ssh.set_key_permissions(key_path)
117
+ opts = {:port=>(port || 22),:keys=>key_path}
86
118
  if Ssh.needs_gateway?(node)
87
- gname,gkey,gport,guser = Ssh.gateway(node).ie{|h| ['name','key','port','user'].map{|k| h[k]}}
88
- gkey_path = "#{Base.root}/#{gkey}"
89
- gopts = {:port=>(gport || 22),:keys=>gkey_path}
90
- result = Net::SSH::Gateway.run(gname,guser,name,user,command,gopts,opts)
119
+ gname,gkey,gport,guser = Ssh.gateway(node).ie{|h| ['name','key','port','user'].map{|k| h[k]}}
120
+ gkey_path = "#{Base.root}/#{gkey}"
121
+ gopts = {:port=>(gport || 22),:keys=>gkey_path}
122
+ Net::SSH::Gateway.run(gname,guser,name,user,cmd,gopts,opts)
91
123
  else
92
- Net::SSH.start(name,user,opts) do |ssh|
93
- result = ssh.run(command)
94
- end
95
- end
96
- #delete remote dir if necessary
97
- if rem_dir
98
- del_cmd = "rm -rf #{rem_dir}"
99
- if su_user
100
- del_cmd = %{sudo su #{su_user} -c "#{del_cmd}"}
124
+ Net::SSH.start(name,user,opts) do |ssh|
125
+ ssh.run(cmd)
101
126
  end
102
- Ssh.run(node,del_cmd)
103
127
  end
104
- result
105
128
  end
106
129
 
107
130
  def Ssh.read(node,path)
108
- Ssh.run(node,"cat #{path}")
131
+ Ssh.fire!(node,"cat #{path}")
109
132
  end
110
133
 
111
134
  def Ssh.write(node,fdata,to_path,binary=false)
@@ -153,11 +176,20 @@ module Mobilize
153
176
 
154
177
  def Ssh.run_by_stage_path(stage_path)
155
178
  s = Stage.where(:path=>stage_path).first
179
+ u = s.job.runner.user
156
180
  params = s.params
157
181
  node, command = [params['node'],params['cmd']]
158
182
  file_hash = Ssh.file_hash_by_stage_path(stage_path)
159
183
  su_user = s.params['su_user']
160
- Ssh.run(node,command,file_hash,su_user)
184
+ if su_user and !Ssh.sudoers(node).include?(u.name)
185
+ raise "You do not have su permissions for this node"
186
+ elsif su_user.nil? and Ssh.su_all_users(node)
187
+ su_user = u.name
188
+ end
189
+ out_tsv = Ssh.run(node,command,file_hash,su_user)
190
+ #use Gridfs to cache result
191
+ out_url = "gridfs://#{s.path}/out"
192
+ Dataset.write_to_url(out_url,out_tsv)
161
193
  end
162
194
  end
163
195
  end
@@ -1,5 +1,5 @@
1
1
  module Mobilize
2
2
  module Ssh
3
- VERSION = "1.0.7"
3
+ VERSION = "1.0.9"
4
4
  end
5
5
  end
data/lib/samples/ssh.yml CHANGED
@@ -2,17 +2,23 @@ development:
2
2
  tmp_file_dir: "tmp/file/"
3
3
  nodes:
4
4
  dev_node:
5
+ sudoers: [sudo_user]
6
+ su_all_users: true
5
7
  host: {name: dev-host.com, key: "config/mobilize/ssh_private.key", port: 22, user: host_user}
6
8
  gateway: {name: dev-gateway.com, key: "config/mobilize/ssh_private.key", port: 22, user: gateway_user}
7
9
  test:
8
10
  tmp_file_dir: "tmp/file/"
9
11
  nodes:
10
12
  test_node:
13
+ sudoers: [sudo_user]
14
+ su_all_users: true
11
15
  host: {name: test-host.com, key: "config/mobilize/ssh_private.key", port: 22, user: host_user}
12
16
  gateway: {name: test-gateway.com, key: "config/mobilize/ssh_private.key", port: 22, user: gateway_user}
13
17
  production:
14
18
  tmp_file_dir: "tmp/file/"
15
19
  nodes:
16
20
  prod_node:
21
+ sudoers: [sudo_user]
22
+ su_all_users: true
17
23
  host: {name: prod-host.com, key: "config/mobilize/ssh_private.key", port: 22, user: host_user}
18
24
  gateway: {name: prod-gateway.com, key: "config/mobilize/ssh_private.key", port: 22, user: gateway_user}
data/mobilize-ssh.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
- gem.add_runtime_dependency "mobilize-base","1.0.8"
19
+ gem.add_runtime_dependency "mobilize-base","1.0.9"
20
20
  gem.add_runtime_dependency "net-ssh"
21
21
  gem.add_runtime_dependency "net-scp"
22
22
  gem.add_runtime_dependency "net-ssh-gateway"
@@ -43,9 +43,9 @@ describe "Mobilize" do
43
43
  ssh_job_rows.map{|j| r.jobs(j['name'])}.each{|j| j.delete if j}
44
44
  jobs_sheet.add_or_update_rows(ssh_job_rows)
45
45
 
46
- puts "job row added, force enqueued runner, wait 120s"
46
+ puts "job row added, force enqueue runner, wait 150s"
47
47
  r.enqueue!
48
- sleep 120
48
+ sleep 150
49
49
 
50
50
  puts "update job status and activity"
51
51
  r.update_gsheet(gdrive_slot)
@@ -6,13 +6,13 @@
6
6
  stage2: 'gsheet.write source:"stage1", target:"Runner_mobilize(test)/test_ssh_1.out"'
7
7
  - name: test_ssh_2
8
8
  active: true
9
- trigger: once
9
+ trigger: "after test_ssh_1"
10
10
  status: ""
11
11
  stage1: 'ssh.run node:"test_node", cmd:"sh code.sh", su_user:"root", source:"Runner_mobilize(test)/code.sh"'
12
12
  stage2: 'gsheet.write source:"stage1", target:"Runner_mobilize(test)/test_ssh_2.out"'
13
13
  - name: test_ssh_3
14
14
  active: true
15
- trigger: once
15
+ trigger: "after test_ssh_2"
16
16
  status: ""
17
17
  stage1: 'ssh.run node:"test_node", cmd:"whoami"'
18
18
  stage2: 'gsheet.write source:"stage1", target:"Runner_mobilize(test)/test_ssh_3.out"'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mobilize-ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-16 00:00:00.000000000 Z
12
+ date: 2012-12-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mobilize-base
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.0.8
21
+ version: 1.0.9
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 1.0.8
29
+ version: 1.0.9
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: net-ssh
32
32
  requirement: !ruby/object:Gem::Requirement