autossh 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 422069342456b2404cae7a17b2c5d295107406b2
4
+ data.tar.gz: 10a10355f20583451dcb018d657afb8ead2c7e9a
5
+ SHA512:
6
+ metadata.gz: fe533461dd980868e15f4fadd8ed0eaf91b3b2eb8f9ed95d64e083aa8042f6e2fd7f91e01e471e8c00e79bdec68d947c9843f17457de83147951cfa277433967
7
+ data.tar.gz: 0daa89f3800cb89908093fe642e303bd1e62c386307540beeb253c8e91b69cd02164a0e3ede23a0d1bcd6edf963f2aa5e6a876422d50378b0c9b8718cc355925
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .idea/
2
+ .assh-*
3
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gem 'colorize'
3
+ gem 'aws-sdk'
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ aws-sdk (1.54.0)
5
+ aws-sdk-v1 (= 1.54.0)
6
+ aws-sdk-v1 (1.54.0)
7
+ json (~> 1.4)
8
+ nokogiri (>= 1.4.4)
9
+ colorize (0.7.3)
10
+ json (1.8.1)
11
+ mini_portile (0.6.0)
12
+ nokogiri (1.6.3.1)
13
+ mini_portile (= 0.6.0)
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ aws-sdk
20
+ colorize
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ Available on Rubygems at https://rubygems.org/gems/autossh
2
+
3
+ Github repository at https://github.com/paul-ridgway/autossh
4
+
5
+ To Install
6
+ ==========
7
+
8
+ 1. Clone the repository
9
+
10
+ 2. Ensure aash is available on the PATH:
11
+
12
+ ln -s /full/path/to/assh /usr/local/bin/assh
13
+
14
+
15
+ To do
16
+ =====
17
+
18
+ 1. Example configurations
19
+
20
+ 2. Safely handle no config (make dir, etc)
21
+
22
+ 3. Validate config files
23
+
24
+ 4. Gemify?
25
+
26
+ 5. Command line override config path (to test examples, and other uses)
27
+
28
+ 6. Decent logger/log levels, etc
29
+
30
+ 7. Tests
@@ -0,0 +1,6 @@
1
+ _foo()
2
+ {
3
+ local cur=${COMP_WORDS[COMP_CWORD]}
4
+ COMPREPLY=( $(compgen -W "alpha beta bar baz" -- $cur) )
5
+ }
6
+ complete -F _foo foo
data/autossh.gemspec ADDED
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'autossh'
3
+ s.version = '0.0.3'
4
+ s.date = '2015-02-01'
5
+ s.summary = "AutoSSH"
6
+ s.description = "An SSH connection helper"
7
+ s.authors = ["Paul Ridgway"]
8
+ s.email = 'myself@paulridgway.co.uk'
9
+ s.homepage = 'https://github.com/paul-ridgway/autossh'
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = `git ls-files -- test/*`.split("\n")
13
+
14
+ s.executables << 'assh'
15
+ end
data/bin/assh ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'autossh'
3
+
4
+ Assh::Command.new(ARGV).execute!
@@ -0,0 +1,28 @@
1
+ ---
2
+
3
+ Includes: [example_include.yml, example_aws.yml, random.yml]
4
+
5
+ Port: 22
6
+ IdentityFile: ~/.ssh/id_rsa
7
+
8
+ Groups:
9
+
10
+ - Group: Home
11
+ Port: 22
12
+ User: other
13
+ Hosts:
14
+ - Host: nas
15
+ HostName: 192.168.1.1
16
+
17
+ - Group: Personal
18
+ Port: 22
19
+ User: me
20
+ Hosts:
21
+ - Host: a1-vm
22
+ HostName: 1a-vm.example.com
23
+ - Host: 2b-vm
24
+ HostName: 2b-vm.example.com
25
+ - Host: 3c-vm
26
+ HostName: 3c-vm.example.com
27
+ - Host: 4d
28
+ HostName: 4d.example.com
@@ -0,0 +1,8 @@
1
+ ---
2
+
3
+ Provider: aws
4
+
5
+ NameMatch: (.*?\..*?)\.
6
+
7
+ AccessKeyId: someKey
8
+ SecretAccessKey: someSecret
@@ -0,0 +1,43 @@
1
+ ---
2
+
3
+ Groups:
4
+ - Group: Blade Custer
5
+ Port: 2212
6
+ User: bladeuser
7
+ IdentityFile: ~/.ssh/blade_key
8
+ StrictHostKeyChecking: no
9
+ UserKnownHostsFile: /dev/null
10
+ LogLevel: quiet
11
+ Hosts:
12
+ - Host: node-01
13
+ HostName: 10.10.11.101
14
+ - Host: node-02
15
+ HostName: 10.10.11.102
16
+ - Host: node-03
17
+ HostName: 10.10.11.103
18
+ - Host: node-04
19
+ HostName: 10.10.11.104
20
+ - Host: node-05
21
+ HostName: 10.10.11.105
22
+ - Host: node-06
23
+ HostName: 10.10.11.106
24
+ - Host: node-07
25
+ HostName: 10.10.11.107
26
+ - Host: node-08
27
+ HostName: 10.10.11.108
28
+ - Host: node-09
29
+ HostName: 10.10.11.109
30
+ - Host: node-10
31
+ HostName: 10.10.11.110
32
+ - Host: node-11
33
+ HostName: 10.10.11.111
34
+ - Host: node-12
35
+ HostName: 10.10.11.112
36
+ - Host: node-13
37
+ HostName: 10.10.11.113
38
+ - Host: node-14
39
+ HostName: 10.10.11.114
40
+ - Host: node-15
41
+ HostName: 10.10.11.115
42
+ - Host: node-16
43
+ HostName: 10.10.11.116
@@ -0,0 +1,11 @@
1
+ ---
2
+
3
+ Provider: Random
4
+
5
+ Groups:
6
+ - Group: Test
7
+ User: paul
8
+ IdentityFile: ~/Dropbox/.ssh/floow/id_rsa
9
+ Hosts:
10
+ - Host: test
11
+ HostName: 10.10.10.9
data/lib/autossh.rb ADDED
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'colorize'
3
+
4
+ require_relative 'helpers'
5
+ require_relative 'configuration'
6
+ require_relative 'provider'
7
+ require_relative 'providers/file_provider'
8
+ require_relative 'providers/random_provider'
9
+ require_relative 'providers/aws_provider'
10
+ require_relative 'command'
11
+ require_relative 'generator'
12
+ require_relative 'host'
13
+
14
+ module Assh
15
+
16
+ ROOT = File.expand_path('~/.autossh')
17
+
18
+ GENERATED_CONFIG = "#{ROOT}/.assh-generated-config"
19
+ CONFIG_CACHE = "#{ROOT}/.assh-config-cache"
20
+ CONFIG_CACHE_AT = "#{ROOT}/.assh-config-cached-at"
21
+
22
+ VERSION = '0.0.3'
23
+
24
+ end
data/lib/command.rb ADDED
@@ -0,0 +1,77 @@
1
+ module Assh
2
+
3
+ class Command
4
+
5
+ def initialize(argv)
6
+ @args = argv
7
+ parse_arguments!
8
+
9
+ @configuration = Configuration.new
10
+
11
+ @generator = Generator.new
12
+
13
+ Provider.verbose! if @cmd_generate
14
+
15
+ if @configuration.needs_generating? || @cmd_generate
16
+ puts "Refreshing..."
17
+ Provider.load_configuration!(@configuration, 'config.yml')
18
+ @configuration.save_cache!
19
+ else
20
+ @configuration.load_cache!
21
+ end
22
+
23
+ end
24
+
25
+ def execute!
26
+ if @cmd_ls
27
+ puts "Host List (cached at #{Time.at(@configuration.generated_at)})".green
28
+ max_name = 0
29
+ @configuration.groups.each do |name, hosts|
30
+ hosts.each do |name, host|
31
+ max_name = name.size if name.size > max_name
32
+ end
33
+ end
34
+ @configuration.groups.each do |name, hosts|
35
+ puts " #{name.yellow}"
36
+ hosts = Hash[hosts.sort]
37
+ hosts.each do |name, host|
38
+ padded_name = name + (" " * (max_name - name.size))
39
+ puts " #{padded_name.light_white} #{"-".green} #{host.address.cyan}"
40
+ end
41
+ end
42
+ elsif @cmd_generate
43
+ puts "Generating config in #{@generator.output_file}"
44
+ generate!
45
+ puts "Done"
46
+ else
47
+ generate!
48
+ execute_default!
49
+ end
50
+ end
51
+
52
+ private
53
+ def parse_arguments!
54
+ return unless @args.size > 0
55
+ first_arg = @args[0].downcase
56
+ if first_arg == 'ls'
57
+ @cmd_ls = true
58
+ elsif first_arg == 'generate'
59
+ @cmd_generate = true
60
+ end
61
+ end
62
+
63
+ def generate!
64
+ #Generates up-to-date config
65
+ @generator.run!(@configuration.hosts)
66
+ end
67
+
68
+ def execute_default!
69
+ # Generates safe args and replaces assh process with ssh call
70
+ args = @args.map { |x| x.include?(' ') ? "\"#{x}\"" : x }.join(' ')
71
+ command = "ssh -F #{Assh::GENERATED_CONFIG} #{args}"
72
+ exec(command)
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,55 @@
1
+ module Assh
2
+
3
+ class Configuration
4
+
5
+ attr_accessor :hosts, :groups
6
+
7
+ def initialize
8
+ @hosts = {}
9
+ @groups = {}
10
+ end
11
+
12
+ def add_host(group_name, host_name, host)
13
+ puts "WARNING: Duplicate host named: #{name}. Only latest host is included" if @hosts[host_name]
14
+
15
+ @groups[group_name] = {} unless @groups.has_key?(group_name)
16
+ @groups[group_name][host_name] = host
17
+ @hosts[host_name] = host
18
+ end
19
+
20
+ #TODO: Move generated-at to here and call config-cached-at
21
+
22
+ def save_cache!(config_file = File.expand_path(Assh::CONFIG_CACHE),
23
+ timestamp_file = File.expand_path(Assh::CONFIG_CACHE_AT))
24
+ cache = {
25
+ hosts: @hosts,
26
+ groups: @groups
27
+ }
28
+ File.open(config_file, 'w') { |f| f << cache.to_yaml }
29
+ File.open(timestamp_file, 'w') { |f| f << current_time }
30
+
31
+ end
32
+
33
+ def load_cache!(config_file = File.expand_path(Assh::CONFIG_CACHE))
34
+ cache = YAML::load_file(config_file)
35
+ @hosts = cache[:hosts]
36
+ @groups = cache[:groups]
37
+ end
38
+
39
+ def needs_generating?(timestamp_file = File.expand_path(Assh::CONFIG_CACHE_AT))
40
+ (current_time - generated_at(timestamp_file)) > 72000
41
+ end
42
+
43
+ def generated_at(timestamp_file = File.expand_path(Assh::CONFIG_CACHE_AT))
44
+ return File.read(timestamp_file).to_i if File.exists?(timestamp_file)
45
+ 0
46
+ end
47
+
48
+ private
49
+ def current_time
50
+ Time.now.to_i
51
+ end
52
+
53
+ end
54
+
55
+ end
data/lib/generator.rb ADDED
@@ -0,0 +1,20 @@
1
+ module Assh
2
+ class Generator
3
+
4
+ attr_accessor :output_file
5
+
6
+ def initialize(output_file = File.expand_path(Assh::GENERATED_CONFIG))
7
+ @output_file = output_file
8
+ end
9
+
10
+ def run!(hosts)
11
+ File.open(@output_file, 'w') do |f|
12
+ hosts.each do |_, host|
13
+ f << host.to_ssh_config
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
data/lib/helpers.rb ADDED
@@ -0,0 +1,11 @@
1
+ class String
2
+ def underscore
3
+ self.gsub(/::/, '/').
4
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
5
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
6
+ tr(" ", "-").
7
+ tr("(", "").
8
+ tr(")", "").
9
+ downcase
10
+ end
11
+ end
data/lib/host.rb ADDED
@@ -0,0 +1,46 @@
1
+ require_relative 'providers/file_provider'
2
+
3
+ module Assh
4
+
5
+ class Host
6
+
7
+ PORT_KEY = "Port"
8
+ HOST_KEY = Assh::FileProvider::HOST_KEY
9
+ HOSTNAME_KEY = "HostName"
10
+ HOSTS_KEY = Assh::FileProvider::HOSTS_KEY
11
+ GROUP_KEY = Assh::FileProvider::GROUP_KEY
12
+ GROUPS_KEY = Assh::FileProvider::GROUPS_KEY
13
+
14
+
15
+ attr_accessor :name, :hostname, :port
16
+
17
+ def initialize(params)
18
+ raise 'Unexpected params type' unless params.is_a? Hash
19
+ @name = params.delete(HOST_KEY)
20
+ @hostname = params.delete(HOSTNAME_KEY)
21
+ @port = params.delete(PORT_KEY) || 22
22
+ @params = params
23
+ end
24
+
25
+ def address
26
+ "#{hostname}:#{port}"
27
+ end
28
+
29
+ def to_s
30
+ "#{name} - #{hostname}:#{port}"
31
+ end
32
+
33
+ def to_ssh_config
34
+ f = ""
35
+ f << "Host #{name}\n"
36
+ f << " Hostname #{hostname}\n"
37
+ f << " Port #{port}\n"
38
+ @params.each do |k,v|
39
+ f << " #{k} #{v}\n"
40
+ end
41
+ f
42
+ end
43
+
44
+ end
45
+
46
+ end
data/lib/provider.rb ADDED
@@ -0,0 +1,61 @@
1
+ module Assh
2
+
3
+ class Provider
4
+
5
+ @@verbose = false
6
+
7
+ @@providers ||= {}
8
+
9
+ def initialize(configuration)
10
+ @configuration = configuration
11
+ end
12
+
13
+ def self.load_configuration!(configuration, file)
14
+ status "Loading: #{file}"
15
+
16
+ config = YAML::load_file(File.expand_path(file, Assh::ROOT))
17
+
18
+ includes = config.delete(Assh::FileProvider::INCLUDES_KEY) || []
19
+
20
+ provider_name = (config.delete('Provider') || 'file').downcase
21
+ provider_class = @@providers[provider_name]
22
+ raise "Provider not found: #{provider_name}" unless provider_class
23
+
24
+ provider = provider_class.new(configuration)
25
+ provider.parse_config!(config)
26
+
27
+ includes.each do |inc|
28
+ Provider.load_configuration!(configuration, File.expand_path(inc, ROOT))
29
+ end
30
+
31
+ provider
32
+ end
33
+
34
+ def parse_config!(config)
35
+ raise 'parse_config! must be overridden'
36
+ end
37
+
38
+ def add_host(group_name, host_name, host)
39
+ @configuration.add_host(group_name, host_name, host)
40
+ end
41
+
42
+ def self.status(message = "", inline = false)
43
+ return unless @@verbose
44
+ if inline
45
+ print message
46
+ else
47
+ puts message
48
+ end
49
+ end
50
+
51
+ def self.verbose!
52
+ @@verbose = true
53
+ end
54
+
55
+ def self.register_provider!(name, clazz)
56
+ @@providers[name] = clazz
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,67 @@
1
+ require 'aws-sdk'
2
+
3
+ module Assh
4
+
5
+ class AwsProvider < Assh::Provider
6
+
7
+ def initialize(configuration)
8
+ super(configuration)
9
+ end
10
+
11
+ def parse_config!(config)
12
+ return unless config
13
+ raise 'Unexpected config type' unless config.is_a? Hash
14
+
15
+ name_match = config.delete 'NameMatch'
16
+ access_key_id = config.delete 'AccessKeyId'
17
+ secret_access_key = config.delete 'SecretAccessKey'
18
+
19
+ AWS.config(
20
+ access_key_id: access_key_id,
21
+ secret_access_key: secret_access_key)
22
+
23
+
24
+ Provider::status "Downloading regions list..."
25
+
26
+ regions = AWS.ec2.regions.map { |r| r.name }
27
+
28
+ Provider::status "Downloading instances..."
29
+
30
+ regions.each do |region|
31
+
32
+ ec2 = AWS::EC2.new(
33
+ access_key_id: access_key_id,
34
+ secret_access_key: secret_access_key,
35
+ region: region)
36
+
37
+ hosts = {}
38
+ ec2.instances.each do |i|
39
+ Provider::status '.', true
40
+ name = (i.tags.Name || i.instance_id).underscore
41
+ ip = i.public_ip_address
42
+ hosts[name] = ip
43
+ end
44
+
45
+ hosts.each do |name, ip|
46
+
47
+ if name_match
48
+ m = Regexp.new(name_match).match(name)
49
+ if m
50
+ name = m.captures[0]
51
+ end
52
+ end
53
+
54
+ add_host(region, name, Host.new(config.merge({'Host' => name, 'HostName' => ip})))
55
+ end
56
+
57
+ end
58
+
59
+ Provider::status
60
+
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ Assh::Provider.register_provider!("aws", Assh::AwsProvider)
@@ -0,0 +1,54 @@
1
+ require_relative '../provider'
2
+ require 'yaml'
3
+
4
+ module Assh
5
+
6
+ class FileProvider < Provider
7
+
8
+ ROOT = File.expand_path('~/.autossh')
9
+
10
+ INCLUDES_KEY = "Includes"
11
+ HOST_KEY = "Host"
12
+ HOSTS_KEY = "Hosts"
13
+ GROUP_KEY = "Group"
14
+ GROUPS_KEY = "Groups"
15
+
16
+ def initialize(configuration)
17
+ super(configuration)
18
+ end
19
+
20
+ def parse_config!(config)
21
+ return unless config
22
+ raise 'Unexpected config type' unless config.is_a? Hash
23
+
24
+ groups = config.delete(GROUPS_KEY)
25
+
26
+ if hosts = config.delete(HOSTS_KEY)
27
+ groups << {GROUP_KEY => 'ungrouped', HOSTS_KEY => hosts}
28
+ end
29
+
30
+ groups.each { |g| parse_group!(config, g) }
31
+ end
32
+
33
+ private
34
+ def parse_group!(parent_config, group)
35
+ return unless group
36
+ parent_config ||= {}
37
+ name = group.delete(GROUP_KEY)
38
+ hosts = group.delete(HOSTS_KEY)
39
+ hosts.each { |h| parse_host!(name, parent_config.merge(group), h) }
40
+ end
41
+
42
+ def parse_host!(group_name, parent_config, host)
43
+ return unless host
44
+ parent_config ||= {}
45
+ name = host[HOST_KEY]
46
+
47
+ add_host(group_name, name, Host.new(parent_config.merge(host)))
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ Assh::Provider.register_provider!("file", Assh::FileProvider)
@@ -0,0 +1,23 @@
1
+ require_relative '../provider'
2
+ require 'yaml'
3
+
4
+ module Assh
5
+
6
+ class RandomProvider < Provider
7
+
8
+ def initialize(configuration)
9
+ super(configuration)
10
+ end
11
+
12
+ def parse_config!(config)
13
+ return unless config
14
+ raise 'Unexpected config type' unless config.is_a? Hash
15
+
16
+ add_host('Random', 'rnd', Host.new({'Host' => 'rnd', 'HostName' => '123.1.2.3'}))
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+
23
+ Assh::Provider.register_provider!("random", Assh::RandomProvider)
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: autossh
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Paul Ridgway
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: An SSH connection helper
14
+ email: myself@paulridgway.co.uk
15
+ executables:
16
+ - assh
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - README.md
24
+ - assh_completion.sh
25
+ - autossh.gemspec
26
+ - bin/assh
27
+ - examples/config.yml
28
+ - examples/example_aws.yml
29
+ - examples/example_include.yml
30
+ - examples/random.yml
31
+ - lib/autossh.rb
32
+ - lib/command.rb
33
+ - lib/configuration.rb
34
+ - lib/generator.rb
35
+ - lib/helpers.rb
36
+ - lib/host.rb
37
+ - lib/provider.rb
38
+ - lib/providers/aws_provider.rb
39
+ - lib/providers/file_provider.rb
40
+ - lib/providers/random_provider.rb
41
+ homepage: https://github.com/paul-ridgway/autossh
42
+ licenses: []
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 2.4.5
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: AutoSSH
64
+ test_files: []