ssh_bro 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1b088e5bb6d1e18b88d40b54a2c5c7cb270e2a7c
4
+ data.tar.gz: c7e31787f2851853e31b5c98e79d95ab590f1f5d
5
+ SHA512:
6
+ metadata.gz: 283e4c5c68dc26273b1d405300f6f756a2704bed6dd56d1fb8405f555558604896238d4d84a8b143a8dcaf1fb59eda6a8081bb3ff0d88e43473d745339608cf2
7
+ data.tar.gz: db7e924e5754cefa2999a406ac111677aa70bb241a12d85a0f9f02a19f41d8f774da062b89e3c3a1894885dd685157dfb4434282b2fa6cb75bf9a9a0f848b5fe
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ssh_bro.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Daniel Leavitt
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ # SSHBro
2
+
3
+ Replaces a fella's SSH Config (~/.ssh/config) with some stuff from a Google doc.
4
+
5
+ This gives you handy bookmarks for all them servers and tab-completion if you're using a decent shell.
6
+
7
+ ## Installation
8
+
9
+ Like this:
10
+
11
+ $ gem install ssh_bro
12
+
13
+ Ruby 1.9.3+ blah blah.
14
+
15
+ ## Usage
16
+
17
+ Run it:
18
+
19
+ $ sshbro
20
+
21
+ It will prompt you for things. To update your SSH config file:
22
+
23
+ $ sshbro > ~/.ssh/config
24
+
25
+ ## TODO:
26
+
27
+ - Allow config file templates.
28
+ - Allow per-host templates.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ Signal.trap("INT") { exit 1 }
4
+
5
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
6
+
7
+ require 'ssh_bro/cli'
8
+
9
+ SSHBro::CLI.new.run
@@ -0,0 +1,94 @@
1
+ require 'csv'
2
+
3
+ require 'google_doc_seed'
4
+
5
+ require "ssh_bro/version"
6
+
7
+ class String
8
+ def yaml_truthy?
9
+ ['y', 'yes', 'true'].include?(self.downcase)
10
+ end
11
+
12
+ def yaml_falsey?
13
+ ['n', 'no', 'false'].include?(self.downcase)
14
+ end
15
+
16
+ def to_yaml_boolean
17
+ if self.yaml_truthy?
18
+ return true
19
+ elsif self.yaml_falsey?
20
+ return false
21
+ else
22
+ self
23
+ end
24
+ end
25
+ end
26
+
27
+ module SSHBro
28
+ class Retriever
29
+ def initialize(token)
30
+ @seeder = GoogleDocSeed.new(token)
31
+ end
32
+
33
+ def retrieve(doc_id)
34
+ @csv = CSV.parse(@seeder.to_csv_string(doc_id), {
35
+ headers: true,
36
+ header_converters: :symbol,
37
+ converters: [
38
+ -> (f) { f.respond_to?(:empty?) && f.empty? ? nil : f },
39
+ -> (f) { f.respond_to?(:gsub) ? f.gsub(/\s+$/, '') : f },
40
+ -> (f) { f.respond_to?(:to_yaml_boolean) ? f.to_yaml_boolean : f },
41
+ :all
42
+ ]
43
+ }).map(&:to_hash)
44
+ .reject { |h| h[:aliases].nil? || h[:aliases].empty? || h[:use] != true }
45
+ end
46
+
47
+ def to_ssh_hosts
48
+ # TODO: validate
49
+ hosts = @csv.map { |h| h.merge(text: apply_ssh_template(h)) }
50
+ groups = hosts.group_by { |h| [h[:provider], h[:owner]].join(" - ") }
51
+
52
+ groups.map do |group_name, group|
53
+ header = ('#' * 45) + "\n# #{group_name}\n" + ('#' * 45) + "\n\n"
54
+ body = group.map { |h| h[:text] }.join("\n\n")
55
+ header + body
56
+ end.join("\n\n")
57
+ end
58
+
59
+ def apply_ssh_template(h)
60
+ lines = [ "Host #{h[:aliases]}",
61
+ "Hostname #{h[:hostname]}",
62
+ "User #{h[:user]}",
63
+ "RemoteForward 52698 localhost:52698" ].join("\n ")
64
+
65
+
66
+ lines.prepend("# #{h[:comment]}\n\n") if h[:comment]
67
+
68
+ lines
69
+ end
70
+
71
+ def to_ansible_hosts
72
+ hosts = @csv.map { |h| h.merge(text: apply_ansible_template(h)) }
73
+ groups = hosts.group_by do |h|
74
+ "; " + [h[:provider], h[:owner]].join(" - ") + "\n[#{h[:group]}]\n"
75
+ end
76
+
77
+ groups.map do |group_name, group|
78
+ body = group.map { |h| h[:text] }.join("\n")
79
+ group_name + body
80
+ end.join("\n\n")
81
+ end
82
+
83
+ def apply_ansible_template(h)
84
+ words = [ h[:aliases].split(' ').first,
85
+ "ansible_ssh_host=#{h[:hostname]}",
86
+ "ansible_ssh_user=#{h[:user]}" ]
87
+ words.join(" ")
88
+ end
89
+
90
+ def to_yaml
91
+ @csv.map { |h| h.reduce({}) { |memo,(k,v)| memo.merge(k.to_s => v) } }.to_yaml
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,79 @@
1
+ require 'cgi'
2
+ require 'uri'
3
+ require 'yaml'
4
+ require 'json'
5
+ require 'net/http'
6
+ require 'fileutils'
7
+
8
+ require 'ssh_bro'
9
+
10
+ module SSHBro
11
+ class CLI
12
+ CLIENT_ID = '537798680864-nmntkirifcaso227mu8svaonjoo3q5i9.apps.googleusercontent.com'
13
+ CLIENT_SECRET = '1VSrX4z1f0gM_KR9Y4oQSoke'
14
+
15
+ def run
16
+ creds_path = File.join(File.expand_path('~'), '.ssh', '.sshbro.yml')
17
+
18
+ begin
19
+ creds = YAML.load_file(creds_path)
20
+ refresh_token = creds['refresh_token']
21
+ doc_id = creds['doc_id']
22
+ STDERR.puts "Loading credentials from #{creds_path}"
23
+ rescue Errno::ENOENT
24
+ end
25
+
26
+ if refresh_token
27
+ uri = URI('https://accounts.google.com/o/oauth2/token')
28
+ res = Net::HTTP.post_form(uri, refresh_token: refresh_token,
29
+ client_id: CLIENT_ID,
30
+ client_secret: CLIENT_SECRET,
31
+ grant_type: 'refresh_token')
32
+
33
+ access_token = JSON.parse(res.body)['access_token']
34
+ else
35
+ token = GoogleDocSeed.get_access_token(CLIENT_ID, CLIENT_SECRET)
36
+ refresh_token = token['refresh_token']
37
+ access_token = token['access_token']
38
+ save = true
39
+ end
40
+
41
+ unless doc_id
42
+ STDERR.puts 'Please enter the Google Spreadsheet URL: '
43
+ doc_url = STDIN.gets.chomp
44
+ doc_id = CGI.parse(URI.parse(doc_url).query)['key'].first
45
+ save = true
46
+ end
47
+
48
+ if save
49
+ STDERR.puts "Okay to save your refresh to #{creds_path}? (y\\N)"
50
+ if gets.chomp.yaml_truthy?
51
+ File.write(creds_path, {
52
+ 'refresh_token' => refresh_token, 'doc_id' => doc_id
53
+ }.to_yaml)
54
+ end
55
+ end
56
+
57
+ retriever = Retriever.new(access_token)
58
+ retriever.retrieve(doc_id)
59
+
60
+ STDERR.puts "Select an output format"
61
+ STDERR.puts "1: SSH Config"
62
+ STDERR.puts "2: Ansible Hosts"
63
+ STDERR.puts "3: YAML"
64
+
65
+ hosts_string = case STDIN.gets.chomp
66
+ when "1" then retriever.to_ssh_hosts
67
+ when "2" then retriever.to_ansible_hosts
68
+ when "3" then retriever.to_yaml
69
+ else raise "Invalid selection"
70
+ end
71
+
72
+
73
+
74
+ STDERR.puts "\n\n"
75
+
76
+ STDOUT.puts hosts_string
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,3 @@
1
+ module SSHBro
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ssh_bro/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ssh_bro"
8
+ spec.version = SSHBro::VERSION
9
+ spec.authors = ["Daniel Leavitt"]
10
+ spec.email = ["daniel.leavitt@gmail.com"]
11
+ spec.summary = %q{Load SSH config from a Google Doc.}
12
+ spec.description = %q{Load SSH config from a Google Doc.}
13
+ spec.homepage = "https://github.com/dleavitt/ssh_bro"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency 'launchy'
25
+ spec.add_dependency 'google-api-client'
26
+ spec.add_dependency 'google_doc_seed', '~> 0.0.4'
27
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ssh_bro
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Leavitt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: launchy
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: google-api-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: google_doc_seed
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.0.4
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.0.4
83
+ description: Load SSH config from a Google Doc.
84
+ email:
85
+ - daniel.leavitt@gmail.com
86
+ executables:
87
+ - sshbro
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - bin/sshbro
97
+ - lib/ssh_bro.rb
98
+ - lib/ssh_bro/cli.rb
99
+ - lib/ssh_bro/version.rb
100
+ - ssh_bro.gemspec
101
+ homepage: https://github.com/dleavitt/ssh_bro
102
+ licenses:
103
+ - MIT
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 2.0.3
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: Load SSH config from a Google Doc.
125
+ test_files: []