vos 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rake_ext'
2
2
 
3
3
  project(
4
4
  name: "vos",
5
- version: "0.1.0",
5
+ version: "0.1.1",
6
6
  summary: "Virtual Operating System",
7
7
 
8
8
  author: "Alexey Petrushin",
data/lib/vos/box.rb CHANGED
@@ -4,22 +4,33 @@ module Vos
4
4
 
5
5
  attr_accessor :options
6
6
 
7
- def initialize options = {}
8
- @options = options
9
- options[:host] ||= 'localhost'
7
+ def initialize *args
8
+ first = args.first
9
+ if args.empty?
10
+ @driver = Drivers::Local.new
11
+ elsif first.is_a?(String) or first.is_a?(Symbol) or first.is_a?(Hash) and (args.size <= 2)
12
+ if first.is_a? Hash
13
+ options = first
14
+ options[:host] ||= 'localhost'
15
+ else
16
+ options = args[1] || {}
17
+ raise 'invalid arguments' unless options.is_a?(Hash)
18
+ options[:host] = first.to_s
19
+ end
20
+
21
+ @driver = options[:host] == 'localhost' ? Drivers::Local.new(options) : Drivers::Ssh.new(options)
22
+ elsif args.size == 1
23
+ @driver = first
24
+ else
25
+ raise 'invalid arguments'
26
+ end
10
27
  end
11
28
 
12
29
 
13
30
  #
14
31
  # driver
15
32
  #
16
- def driver
17
- unless @driver
18
- klass = options[:host] == 'localhost' ? Drivers::Local : Drivers::Ssh
19
- @driver = klass.new options
20
- end
21
- @driver
22
- end
33
+ attr_reader :driver
23
34
 
24
35
  def open &block
25
36
  driver.open &block
@@ -33,12 +44,13 @@ module Vos
33
44
  # Micelaneous
34
45
  #
35
46
  def inspect
36
- host = options[:host]
37
- if host == 'localhost'
38
- ''
39
- else
40
- host
41
- end
47
+ driver.to_s
48
+ # host = options[:host]
49
+ # if host == 'localhost'
50
+ # ''
51
+ # else
52
+ # host
53
+ # end
42
54
  end
43
55
  alias_method :to_s, :inspect
44
56
  end
@@ -33,6 +33,12 @@ module Vos
33
33
 
34
34
  return code, stdout_and_stderr
35
35
  end
36
+
37
+
38
+ #
39
+ # Other
40
+ #
41
+ def to_s; '' end
36
42
  end
37
43
  end
38
44
  end
@@ -4,142 +4,18 @@ require 'net/sftp'
4
4
  module Vos
5
5
  module Drivers
6
6
  class Ssh < Abstract
7
- module VfsStorage
8
- #
9
- # Attributes
10
- #
11
- def attributes path
12
-
13
- stat = sftp.stat! fix_path(path)
14
- attrs = {}
15
- attrs[:file] = stat.file?
16
- attrs[:dir] = stat.directory?
17
- # stat.symlink?
18
- attrs
19
- rescue Net::SFTP::StatusException
20
- {}
21
- end
22
-
23
- def set_attributes path, attrs
24
- raise 'not supported'
25
- end
26
-
27
- #
28
- # File
29
- #
30
- def read_file path, &block
31
- sftp.file.open fix_path(path), 'r' do |is|
32
- while buff = is.gets
33
- block.call buff
34
- end
35
- end
36
- end
37
-
38
- def write_file path, append, &block
39
- # there's no support for :append in Net::SFTP, so we just mimic it
40
- if append
41
- attrs = attributes(path)
42
- data = if attrs
43
- if attrs[:file]
44
- os = ""
45
- read_file(path){|buff| os << buff}
46
- delete_file path
47
- os
48
- else
49
- raise "can't append to dir!"
50
- end
51
- else
52
- ''
53
- end
54
- write_file path, false do |writer|
55
- writer.call data
56
- block.call writer
57
- end
58
- else
59
- sftp.file.open fix_path(path), 'w' do |os|
60
- writer = -> buff {os.write buff}
61
- block.call writer
62
- end
63
- end
64
- end
65
-
66
- def delete_file remote_file_path
67
- sftp.remove! fix_path(remote_file_path)
68
- end
69
-
70
- # def move_file path
71
- # raise 'not supported'
72
- # end
73
-
74
-
75
- #
76
- # Dir
77
- #
78
- def create_dir path
79
- sftp.mkdir! path
80
- end
81
-
82
- def delete_dir path
83
- exec "rm -r #{path}"
84
- end
85
-
86
- def each path, &block
87
- sftp.dir.foreach path do |stat|
88
- next if stat.name == '.' or stat.name == '..'
89
- if stat.directory?
90
- block.call stat.name, :dir
91
- else
92
- block.call stat.name, :file
93
- end
94
- end
95
- end
96
-
97
- def efficient_dir_copy from, to
98
- from.storage.open_fs do |from_fs|
99
- to.storage.open_fs do |to_fs|
100
- if from_fs.local?
101
- sftp.upload! from.path, fix_path(to.path)
102
- true
103
- elsif to_fs.local?
104
- sftp.download! fix_path(to.path), from.path, :recursive => true
105
- true
106
- else
107
- false
108
- end
109
- end
110
- end
111
- end
112
-
113
- # def move_dir path
114
- # raise 'not supported'
115
- # end
116
-
117
-
118
- #
119
- # Special
120
- #
121
- def tmp &block
122
- tmp_dir = "/tmp/vfs_#{rand(10**3)}"
123
- if block
124
- begin
125
- create_dir tmp_dir
126
- block.call tmp_dir
127
- ensure
128
- delete_dir tmp_dir
129
- end
130
- else
131
- create_dir tmp_dir
132
- tmp_dir
133
- end
134
- end
135
-
136
- def local?; false end
137
- end
7
+ DEFAULT_OPTIONS = {
8
+ config: true
9
+ }
138
10
 
139
11
  def initialize options = {}
140
- super
141
- raise "ssh options not provided!" unless options[:ssh]
142
- raise "invalid ssh options!" unless options[:ssh].is_a?(Hash)
12
+ super
13
+ raise ":host not provided!" unless options[:host]
14
+ @options = DEFAULT_OPTIONS.merge options
15
+
16
+ # config_options = Net::SSH.configuration_for(options[:host])
17
+ # options = DEFAULT_OPTIONS.merge(config_options).merge options
18
+ # raise ":user not provided (provide explicitly or in .ssh/config)!" unless options[:user]
143
19
  end
144
20
 
145
21
 
@@ -160,10 +36,11 @@ module Vos
160
36
  end
161
37
  else
162
38
  unless @ssh
163
- ssh_options = self.options[:ssh].clone
164
- host = options[:host] || raise('host not provided!')
165
- user = ssh_options.delete(:user) || raise('user not provied!')
166
- @ssh = Net::SSH.start(host, user, ssh_options)
39
+ opt = self.options.clone
40
+ host = opt.delete :host #] || raise('host not provided!')
41
+ # user = options.delete(:user) || raise('user not provied!')
42
+
43
+ @ssh = Net::SSH.start(host, nil, opt)
167
44
  @sftp = @ssh.sftp.connect
168
45
  end
169
46
  end
@@ -177,13 +54,11 @@ module Vos
177
54
  end
178
55
  end
179
56
 
180
- def to_s; options[:host] end
181
-
182
-
57
+
183
58
  #
184
59
  # Vfs
185
60
  #
186
- include VfsStorage
61
+ include SshVfsStorage
187
62
  alias_method :open_fs, :open
188
63
 
189
64
 
@@ -209,6 +84,11 @@ module Vos
209
84
  end
210
85
 
211
86
 
87
+ #
88
+ # Micelaneous
89
+ #
90
+ def to_s; options[:host] end
91
+
212
92
  protected
213
93
  attr_accessor :ssh, :sftp
214
94
 
@@ -0,0 +1,135 @@
1
+ module Vos
2
+ module Drivers
3
+ module SshVfsStorage
4
+ #
5
+ # Attributes
6
+ #
7
+ def attributes path
8
+
9
+ stat = sftp.stat! fix_path(path)
10
+ attrs = {}
11
+ attrs[:file] = stat.file?
12
+ attrs[:dir] = stat.directory?
13
+ # stat.symlink?
14
+ attrs
15
+ rescue Net::SFTP::StatusException
16
+ {}
17
+ end
18
+
19
+ def set_attributes path, attrs
20
+ raise 'not supported'
21
+ end
22
+
23
+ #
24
+ # File
25
+ #
26
+ def read_file path, &block
27
+ sftp.file.open fix_path(path), 'r' do |is|
28
+ while buff = is.gets
29
+ block.call buff
30
+ end
31
+ end
32
+ end
33
+
34
+ def write_file path, append, &block
35
+ # there's no support for :append in Net::SFTP, so we just mimic it
36
+ if append
37
+ attrs = attributes(path)
38
+ data = if attrs
39
+ if attrs[:file]
40
+ os = ""
41
+ read_file(path){|buff| os << buff}
42
+ delete_file path
43
+ os
44
+ else
45
+ raise "can't append to dir!"
46
+ end
47
+ else
48
+ ''
49
+ end
50
+ write_file path, false do |writer|
51
+ writer.call data
52
+ block.call writer
53
+ end
54
+ else
55
+ sftp.file.open fix_path(path), 'w' do |os|
56
+ writer = -> buff {os.write buff}
57
+ block.call writer
58
+ end
59
+ end
60
+ end
61
+
62
+ def delete_file remote_file_path
63
+ sftp.remove! fix_path(remote_file_path)
64
+ end
65
+
66
+ # def move_file path
67
+ # raise 'not supported'
68
+ # end
69
+
70
+
71
+ #
72
+ # Dir
73
+ #
74
+ def create_dir path
75
+ sftp.mkdir! path
76
+ end
77
+
78
+ def delete_dir path
79
+ exec "rm -r #{path}"
80
+ end
81
+
82
+ def each path, &block
83
+ sftp.dir.foreach path do |stat|
84
+ next if stat.name == '.' or stat.name == '..'
85
+ if stat.directory?
86
+ block.call stat.name, :dir
87
+ else
88
+ block.call stat.name, :file
89
+ end
90
+ end
91
+ end
92
+
93
+ def efficient_dir_copy from, to
94
+ from.storage.open_fs do |from_fs|
95
+ to.storage.open_fs do |to_fs|
96
+ if from_fs.local?
97
+ sftp.upload! from.path, fix_path(to.path)
98
+ true
99
+ elsif to_fs.local?
100
+ sftp.download! fix_path(to.path), from.path, :recursive => true
101
+ true
102
+ else
103
+ false
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ # def move_dir path
110
+ # raise 'not supported'
111
+ # end
112
+
113
+
114
+ #
115
+ # Special
116
+ #
117
+ def tmp &block
118
+ tmp_dir = "/tmp/vfs_#{rand(10**3)}"
119
+ if block
120
+ begin
121
+ create_dir tmp_dir
122
+ block.call tmp_dir
123
+ ensure
124
+ delete_dir tmp_dir
125
+ end
126
+ else
127
+ create_dir tmp_dir
128
+ tmp_dir
129
+ end
130
+ end
131
+
132
+ def local?; false end
133
+ end
134
+ end
135
+ end
@@ -12,19 +12,19 @@ module Vos
12
12
  file '/etc/profile' ## file '/etc/environment'
13
13
  end
14
14
 
15
- def append_to_environment file, reload = true
16
- raise "#{file} must be an Entry" unless file.is_a? Vfs::Entry
17
-
18
- env_ext = dir '/etc/profile_ext'
19
-
20
- remote_file = env_ext[file.name]
21
- file.copy_to! remote_file
22
-
23
- require_clause = "source #{remote_file.path}"
24
- env_file.append "\n#{require_clause}\n" unless env_file.content.include? require_clause
25
-
26
- reload_env if reload
27
- end
15
+ # def append_to_environment file, reload = true
16
+ # raise "#{file} must be an Entry" unless file.is_a? Vfs::Entry
17
+ #
18
+ # env_ext = dir '/etc/profile_ext'
19
+ #
20
+ # remote_file = env_ext[file.name]
21
+ # file.copy_to! remote_file
22
+ #
23
+ # require_clause = "source #{remote_file.path}"
24
+ # env_file.append "\n#{require_clause}\n" unless env_file.content.include? require_clause
25
+ #
26
+ # reload_env if reload
27
+ # end
28
28
 
29
29
  def reload_env
30
30
  bash ". #{env_file.path}"
@@ -35,6 +35,15 @@ end
35
35
 
36
36
  module Vfs
37
37
  class File
38
-
38
+ def append_to_environment_of box, reload = true
39
+ raise "#{box} must be an Vos::Box" unless file.is_a? Vos::Box
40
+
41
+ copy_to! box.dir('/etc/profile_ext').file(name)
42
+
43
+ require_clause = "source #{remote_file.path}"
44
+ box.env_file.append "\n#{require_clause}\n" unless env_file.content.include? require_clause
45
+
46
+ box.reload_env if reload
47
+ end
39
48
  end
40
49
  end
data/lib/vos.rb CHANGED
@@ -4,12 +4,12 @@ require 'vos/gems'
4
4
 
5
5
  require 'open3'
6
6
 
7
-
8
7
  %w(
9
8
  support
10
9
 
11
10
  drivers/abstract
12
11
  drivers/local
12
+ drivers/ssh_vfs_storage
13
13
  drivers/ssh
14
14
 
15
15
  box/shell
data/readme.md CHANGED
@@ -1,122 +1,44 @@
1
- # Vfs - Virtual File System
1
+ # Vos - Virtual Operating System
2
2
 
3
- Handy and simple abstraction over any storage that can represent concept of File and Directory (or at least part of it).
4
- The Vfs for File System Storages is the same as ActiveRecord is for Relational Databases.
3
+ Small abstraction over Operating System, mainly it should be used in conjunction with [Virtual File System][vos] tool. Kind of
4
+ Capistrano but without extra stuff and more universal, not forcing You to follow 'The Rails Way'.
5
5
 
6
6
  Currently, there are following implementations available:
7
7
 
8
- - local file system
9
- - remote file system (over ssh)
10
-
11
- ## Goals
12
-
13
- - **handy, simple and clean** API.
14
- - **high performance** - the same as by using low-level storage API, there should be no extra calls **.
15
- - same API for different storages (Local FS, SSH, Hadoop, or any other , ...).
16
- - should work **simultaneously with different storages**.
17
- - small codebase, easy to extend by others.
18
- - simple storage-driver implementation, easy add new storage types (Hadoop DFS, LDAP, Document Oriented DB, In-Memory, ...).
19
-
20
- ** all methods should have the same performance as native system calls, except for :move and :rename. Right now they are implemented
21
- ASAP by using copy+destroy approach, will be fixed as soon as I'll have free time to do it.
8
+ - local os
9
+ - remote os (over ssh)
22
10
 
23
11
  ## Installation
24
12
 
25
- $ gem install vfs
26
13
  $ gem install vos
27
14
 
28
15
  ## Code samples:
29
- gem 'vfs' # Virtual File System
30
- require 'vfs'
31
-
32
16
  gem 'vos' # Virtual Operating System
33
17
  require 'vos'
34
18
 
35
-
36
19
  # Connections, let's deploy our 'cool_app' project from our local box to remote server
37
20
  server = Vfs::Box.new(host: 'cool_app.com', ssh: {user: 'me', password: 'secret'})
38
- me = '~'.to_dir
39
-
40
- cool_app = server['apps/cool_app']
41
- projects = me['projects']
42
-
43
-
44
- # Working with dirs, copying dir from any source to any destination (local/remote/custom_storage_type)
45
- projects['cool_app'].copy_to cool_app
46
-
47
-
48
- # Working with files
49
- dbc = cool_app.file('config/database.yml') # <= the 'config' dir not exist yet
50
- dbc.write("user: root\npassword: secret") # <= now the 'database.yml' and parent 'config' has been created
51
- dbc.content =~ /database/ # => false, we forgot to add the database
52
- dbc.append("\ndatabase: mysql") # let's do it
53
-
54
- dbc.update do |content| # and add host info
55
- content + "\nhost: cool_app.com "
56
- end
57
-
58
- projects['cool_app/config/database.yml']. # or just overwrite it with our local dev version
59
- copy_to! dbc
60
-
61
- # there are also streaming support (read/write/append), please go to specs for docs
62
-
63
-
64
- # Checks
65
- cool_app['config'].exist? # => true
66
- cool_app.dir('config').exist? # => true
67
- cool_app.file('config').exist? # => false
68
-
69
- cool_app['config'].dir? # => true
70
- cool_app['config'].file? # => false
71
-
72
-
73
- # Navigation
74
- config = cool_app['config']
75
- config.parent # => </apps/cool_app>
76
- config['../..'] # => </>
77
- config['../..'].dir? # => true
78
-
79
- cool_app.entries # => list of dirs and files, also support &block
80
- cool_app.files # => list of files, also support &block
81
- cool_app.dirs # => list of dirs, also support &block
82
-
83
-
84
- # For more please go to specs (create/update/move/copy/destroy/...)
85
-
86
- ## Integration with [Vos][vos] (Virtual Operating System)
87
21
 
22
+ server.bash 'ls'
88
23
  server['apps/cool_app'].bash 'rails production'
89
24
 
90
- For more details please go to [Vos][vos] project page.
91
-
92
- # Why?
93
-
94
- To easy my work: with local FS, remote FS (cluster management, deployment automation), and some specific systems like Hadoop DFS.
95
-
96
- Because the API of standard File/Dir/FileUtils classes are just terrible. And there's the reason for it - the goal of thouse tools
97
- is to provide 1-to-1 clone of underlying OS API, instead of provididing handy tool.
98
-
99
- And if you want to use remote FS - things are getting even worse and more complicated (Net::SSH & Net::SFTP use a little
100
- different API than local FS, and you has to remember all thouse little quirks).
25
+ For more details look also to [Virtual File System][vos] project.
26
+ Or checkout configuration I use to control my production servers [My Cluster][my_cluster] in conjunction with small
27
+ configuration tool [Cluster Management][cluster_management].
101
28
 
102
29
  ## TODO
103
30
 
104
31
  ### v 0.1 (all done)
105
32
 
106
- - bash & basic support for
107
- - File.append
108
- - list of entries/files/dirs
109
- - support for efficient copy for Local and SSH storages
110
-
111
- ### v 0.2 (not started)
112
-
113
- - efficient (not copy/destroy) versions of move_to, rename
114
- - glob search for directories: Dir['**/*.yml']
115
- - access via attributes and helpers for unix chmod
116
- - add storages: remote FS over HTTP.
33
+ - bash
34
+ - some handy shortcuts for ubuntu
35
+ - integration with Vos
117
36
 
118
- ### future
37
+ ### v 0.2
119
38
 
120
- - add storages: Hadoop DFS, MongoDB, Amazon S3
39
+ - process management (find/kill/filters/attributes)
40
+ - other os resources management (disk)
121
41
 
122
- [vfs]: http://github.com/alexeypetrushin/vfs
42
+ [vos]: http://github.com/alexeypetrushin/vos
43
+ [cluster_management]: http://github.com/alexeypetrushin/cluster_management
44
+ [my_cluster]: http://github.com/alexeypetrushin/my_cluster
@@ -1,4 +1,6 @@
1
1
  :ssh:
2
2
  :host: some_host.com
3
- :user: some_user
4
- :password: some_password
3
+
4
+ # optional, you can omit and use id_rsa key instead
5
+ # :user: some_user
6
+ # :password: some_password
data/spec/config.yml CHANGED
@@ -1,5 +1,2 @@
1
- :remote_driver:
2
- :host: universal.4ire.net
3
- :ssh:
4
- :user: root
5
- :password: privateprivate
1
+ :ssh_driver:
2
+ :host: universal.4ire.net
@@ -5,7 +5,7 @@ describe Vos::Drivers::Ssh do
5
5
  it_should_behave_like "vfs storage"
6
6
 
7
7
  before :all do
8
- @storage = @driver = Vos::Drivers::Ssh.new(config[:remote_driver])
8
+ @storage = @driver = Vos::Drivers::Ssh.new(config[:ssh_driver])
9
9
  @driver.open
10
10
  end
11
11
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 0
9
- version: 0.1.0
8
+ - 1
9
+ version: 0.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Alexey Petrushin
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-02-08 00:00:00 +03:00
17
+ date: 2011-02-09 00:00:00 +03:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -50,6 +50,7 @@ files:
50
50
  - lib/vos/drivers/local.rb
51
51
  - lib/vos/drivers/specification.rb
52
52
  - lib/vos/drivers/ssh.rb
53
+ - lib/vos/drivers/ssh_vfs_storage.rb
53
54
  - lib/vos/gems.rb
54
55
  - lib/vos/helpers/ubuntu.rb
55
56
  - lib/vos/support.rb