pairhost 0.0.2 → 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.
data/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # Pairhost
2
2
 
3
- Create an EC2 instance for Relevance, Inc. remote pairing! It creates the instance and reports the public DNS name right from the command line.
3
+ Manage EC2 instances for remote pairing the style that Relevance prefers.
4
4
 
5
- ## How To Use
5
+ ## How to Use
6
6
 
7
- # install bundler
8
- bundle install
9
- cp config.example.yml config.yml
10
- # edit the config to use real EC2 & AMI stuff (ask me if you need it)
11
- #TODO: ./pairhost up
7
+ gem install pairhost
8
+ pairhost init
9
+ # edit ~/.pairhost/config.yml to use your real EC2 & AMI settings
10
+ pairhost up
data/Rakefile CHANGED
@@ -1 +1,5 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new
5
+ task :default => :spec
@@ -1,3 +1,3 @@
1
1
  module Pairhost
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/lib/pairhost.rb CHANGED
@@ -12,14 +12,18 @@ module Pairhost
12
12
  def self.config
13
13
  @config ||= begin
14
14
  unless File.exists?(config_file)
15
- abort "No pairhost config found. First run 'pairhost init'."
15
+ abort "pairhost: No config found. First run 'pairhost init'."
16
16
  end
17
17
  YAML.load_file(config_file)
18
18
  end
19
19
  end
20
20
 
21
21
  def self.instance_id
22
- @instance_id ||= File.read(File.expand_path('~/.pairhost/instance')).chomp
22
+ return @instance_id unless @instance_id.nil?
23
+
24
+ file = File.expand_path('~/.pairhost/instance')
25
+ @instance_id = File.read(file).chomp if File.exists?(file)
26
+ return @instance_id
23
27
  end
24
28
 
25
29
  def self.connection
@@ -38,7 +42,7 @@ module Pairhost
38
42
 
39
43
  def self.create(name)
40
44
  server_options = {
41
- "tags" => {"Name" => name,
45
+ "tags" => {"Name" => name,
42
46
  "Created-By-Pairhost-Gem" => VERSION},
43
47
  "image_id" => config['ami_id'],
44
48
  "flavor_id" => config['flavor_id'],
@@ -58,6 +62,7 @@ module Pairhost
58
62
  File.open(File.expand_path('~/.pairhost/instance'), "w") do |f|
59
63
  f.write(instance_id)
60
64
  end
65
+ @instance_id = nil
61
66
  end
62
67
 
63
68
  def self.start(server)
@@ -70,32 +75,56 @@ module Pairhost
70
75
  server.wait_for { state == "stopped" }
71
76
  end
72
77
 
78
+ def self.fetch!
79
+ server = fetch
80
+ abort "pairhost: No instance found. Please create or attach to one." if server.nil?
81
+ server
82
+ end
83
+
73
84
  def self.fetch
74
- connection.servers.get(instance_id) if instance_id
85
+ config
86
+ return instance_id.nil? ? nil : connection.servers.get(instance_id)
75
87
  end
76
88
 
77
89
  class CLI < Thor
78
90
  include Thor::Actions
79
91
 
80
- desc "ssh", "SSH to your pairhost"
81
- def ssh
82
- server = Pairhost.fetch
83
- exec "ssh -A -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=QUIET pair@#{server.dns_name}"
92
+ desc "verify", "Verify the config is in place"
93
+ def verify
94
+ Pairhost.config
84
95
  end
85
96
 
86
- desc "status", "Print the status of your pairhost"
87
- def status
88
- server = Pairhost.fetch
89
- puts "#{server.id}: #{server.tags['Name']}"
90
- puts "State: #{server.state}"
91
- puts server.dns_name if server.dns_name
97
+ desc "init", "Setup your ~/.pairhost directory with default config"
98
+ def init
99
+ if File.exists?(Pairhost.config_file)
100
+ STDERR.puts "pairhost: Already initialized."
101
+ else
102
+ FileUtils.mkdir_p File.dirname(Pairhost.config_file)
103
+ FileUtils.cp(File.dirname(__FILE__) + '/../config.example.yml', Pairhost.config_file)
104
+ end
105
+ end
106
+
107
+ desc "create [NAME]", "Provision a new pairhost; all future commands affect this pairhost"
108
+ def create(name=nil)
109
+ invoke :verify, []
110
+
111
+ if name == nil
112
+ initials = `git config user.initials`.chomp.split("/").map(&:upcase).join(" ")
113
+ name = "Pairhost (#{initials})"
114
+ end
115
+
116
+ puts "Provisioning \"#{name}\"..."
117
+ server = Pairhost.create(name)
118
+ puts "provisioned!"
119
+ invoke :status, []
92
120
  end
93
121
 
94
122
  map "start" => :resume
95
123
 
96
124
  desc "resume", "Start a stopped pairhost"
97
125
  def resume
98
- server = Pairhost.fetch
126
+ invoke :verify
127
+ server = Pairhost.fetch!
99
128
  puts "Starting..."
100
129
  Pairhost.start(server.reload)
101
130
  puts "started!"
@@ -103,20 +132,9 @@ module Pairhost
103
132
  invoke :status
104
133
  end
105
134
 
106
- desc "create", "Provision a new pairhost; all future commands affect this pairhost"
107
- def create
108
- initials = `git config user.initials`.chomp.split("/").map(&:upcase).join(" ")
109
- default_name = "something1 #{initials}"
110
- name = ask_with_default("What to name your pairhost? [#{default_name}]", default_name)
111
- puts "Name will be: #{name}"
112
- puts "Provisioning..."
113
- # server = Pairhost.create(name)
114
- # puts "provisioning!"
115
- # invoke :status
116
- end
117
-
118
135
  desc "up", "Create a new pairhost or start your stopped pairhost"
119
136
  def up
137
+ invoke :verify
120
138
  server = Pairhost.fetch
121
139
 
122
140
  if server
@@ -126,32 +144,42 @@ module Pairhost
126
144
  end
127
145
  end
128
146
 
147
+ desc "status", "Print the status of your pairhost"
148
+ def status
149
+ invoke :verify
150
+ server = Pairhost.fetch!
151
+ puts "#{server.id}: #{server.tags['Name']}"
152
+ puts "State: #{server.state}"
153
+ puts server.dns_name if server.dns_name
154
+ end
155
+
156
+ desc "ssh", "SSH to your pairhost"
157
+ def ssh
158
+ invoke :verify
159
+ server = Pairhost.fetch!
160
+ exec "ssh -A -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=QUIET pair@#{server.dns_name}"
161
+ end
162
+
129
163
  map "halt" => :stop
130
164
  map "shutdown" => :stop
131
165
  map "suspend" => :stop
132
166
 
133
167
  desc "stop", "Stop your pairhost"
134
168
  def stop
135
- server = Pairhost.fetch
169
+ invoke :verify
170
+ server = Pairhost.fetch!
136
171
  puts "Shutting down..."
137
172
  Pairhost.stop(server)
138
173
  puts "shutdown!"
139
174
  end
140
175
 
141
- desc "attach", "All future commands affect this pairhost"
142
- def attach
143
- instance_id = ask("EC2 Instance?")
144
- Pairhost.write_instance_id(instance_id)
145
- invoke :status
146
- end
147
-
148
176
  map "terminate" => :destroy
149
177
 
150
178
  desc "destroy", "Terminate your pairhost"
151
179
  def destroy
152
- server = Pairhost.fetch
180
+ invoke :verify
181
+ server = Pairhost.fetch!
153
182
  confirm = ask("Type 'yes' to confirm deleting '#{server.tags['Name']}'.\n>")
154
-
155
183
  return unless confirm == "yes"
156
184
 
157
185
  puts "Destroying..."
@@ -160,15 +188,25 @@ module Pairhost
160
188
  puts "destroyed!"
161
189
  end
162
190
 
163
- desc "init", "Setup your ~/.pairhost directory with default config"
164
- def init
165
- FileUtils.mkdir_p File.dirname(Pairhost.config_file)
166
- FileUtils.cp(File.dirname(__FILE__) + '/../config.example.yml', Pairhost.config_file)
167
- end
168
-
169
191
  desc "provision", "Freshen the Chef recipes"
170
192
  def provision
171
- puts "coming soon..."
193
+ invoke :verify
194
+ # TODO implement
195
+ puts "Coming soon..."
196
+ end
197
+
198
+ desc "attach INSTANCE", "All future commands affect the pairhost with the given EC2 instance ID"
199
+ def attach(instance_id)
200
+ invoke :verify, []
201
+ Pairhost.write_instance_id(instance_id)
202
+ invoke :status, []
203
+ end
204
+
205
+ desc "detach", "Forget the currently-attached pairhost"
206
+ def detach
207
+ invoke :verify
208
+ # TODO implement
209
+ puts "Coming soon..."
172
210
  end
173
211
 
174
212
  private
data/pairhost.gemspec CHANGED
@@ -8,13 +8,17 @@ Gem::Specification.new do |s|
8
8
  s.authors = ["Larry Karnowski"]
9
9
  s.email = ["larry@hickorywind.org"]
10
10
  s.homepage = "http://www.github.com/karnowski/pairhost"
11
- s.summary = %q{Automate creation of Relevance pairhost EC2 instances.}
12
- s.description = %q{A Vagrant-like command line interface for creating, managing, and using EC2 instances for remote pairing.}
11
+ s.summary = %q{Automate creation of Relevance-style pairhost EC2 instances.}
12
+ s.description = %q{A Vagrant-like command line interface for creating, managing, and using EC2 instances for remote pairing like we do at Relevance.}
13
13
 
14
14
  s.files = `git ls-files`.split("\n")
15
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
17
 
18
- s.add_runtime_dependency "fog", "1.1.2"
19
- s.add_runtime_dependency "thor", "0.14.6"
18
+ s.add_runtime_dependency "fog", "1.3.1"
19
+ s.add_runtime_dependency "thor", "~> 0.15.2"
20
+
21
+ s.add_development_dependency 'rspec', '~> 2.9.0'
22
+ s.add_development_dependency 'bahia', '~> 0.7.2'
23
+ s.add_development_dependency 'rake', '~> 0.9.2.2'
20
24
  end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ def ensure_config_file
5
+ config_file = File.expand_path('~/.pairhost/config.yml')
6
+ return if File.exist?(config_file)
7
+ abort "Pairhost config file was NOT found."
8
+ end
9
+
10
+ def safely_move(source, target)
11
+ if File.exist?(source)
12
+ FileUtils.rm_rf(target)
13
+ FileUtils.mv(source, target)
14
+ end
15
+ end
16
+
17
+ describe Pairhost do
18
+ context "when NO pairhost config is present" do
19
+ let(:config_dir) { File.expand_path('~/.pairhost') }
20
+ let(:backup_dir) { File.expand_path('~/.pairhost_test_backup') }
21
+ let(:config_file) { File.expand_path('~/.pairhost/config.yml') }
22
+
23
+ before(:all) { safely_move config_dir, backup_dir }
24
+ after(:all) { safely_move backup_dir, config_dir }
25
+
26
+ the "attach command returns an error message and failure exit code" do
27
+ pairhost "attach some-instance"
28
+ stderr.should == "pairhost: No config found. First run 'pairhost init'.\n"
29
+ process.should_not be_success
30
+ end
31
+
32
+ %w{create up provision detach status ssh resume stop destroy}.each do |method|
33
+ the "#{method} command returns an error message and failure exit code" do
34
+ pairhost method
35
+ stderr.should == "pairhost: No config found. First run 'pairhost init'.\n"
36
+ process.should_not be_success
37
+ end
38
+ end
39
+
40
+ it "init creates a config directory and file" do
41
+ config_dir.should_not exist_on_filesystem
42
+
43
+ pairhost "init"
44
+
45
+ config_dir.should exist_on_filesystem
46
+ config_file.should exist_on_filesystem
47
+ end
48
+ end
49
+
50
+ context "when a valid pairhost config is present" do
51
+ # NOTE: this assumes that as a developer you're also
52
+ # a user of pairhost and have already called "pairhost init"
53
+ # and configured real AWS credentials.
54
+ before(:all) { ensure_config_file }
55
+
56
+ the "init command complains that the config is already present" do
57
+ pairhost "init"
58
+ stderr.should == "pairhost: Already initialized.\n"
59
+ process.should be_success
60
+ end
61
+
62
+ context "when an instance has NOT been provisioned" do
63
+ let(:instance_file) { File.expand_path('~/.pairhost/instance') }
64
+ let(:backup_file) { File.expand_path('~/.pairhost/instance_test_backup') }
65
+
66
+ before(:all) { FileUtils.mv(instance_file, backup_file) if File.exist?(instance_file) }
67
+ after(:all) { FileUtils.mv(backup_file, instance_file) if File.exist?(backup_file) }
68
+
69
+ # create --> asks to confirm creation
70
+ # up --> asks to confirm creation
71
+ # attach --> multiple branches; with instance id specific and without
72
+ # provision --> not implemented yet
73
+ # detach --> not implemented yet
74
+
75
+ %w{status ssh resume stop destroy}.each do |method|
76
+ the "#{method} command returns an error message and failure exit code" do
77
+ pairhost method
78
+ stderr.should == "pairhost: No instance found. Please create or attach to one.\n"
79
+ process.should_not be_success
80
+ end
81
+ end
82
+ end
83
+
84
+ context "when an instance has been provisioned" do
85
+ # TODO: make sure the instance_id file exists;
86
+ # provision an EC2 instance?
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,18 @@
1
+ require 'bahia'
2
+ require 'pairhost'
3
+
4
+ RSpec.configure do |config|
5
+ config.include Bahia
6
+ config.run_all_when_everything_filtered = true
7
+ config.filter_run :focused => true
8
+ config.filter_run_excluding :disabled => true
9
+ config.alias_example_to :fit, :focused => true
10
+ config.alias_example_to :the
11
+ config.color_enabled = true
12
+ end
13
+
14
+ RSpec::Matchers.define :exist_on_filesystem do |name|
15
+ match do |name|
16
+ File.exist?(name)
17
+ end
18
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pairhost
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
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-04-25 00:00:00.000000000 Z
12
+ date: 2012-05-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.1.2
21
+ version: 1.3.1
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,25 +26,73 @@ dependencies:
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 1.1.2
29
+ version: 1.3.1
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: thor
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
- - - '='
35
+ - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: 0.14.6
37
+ version: 0.15.2
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
- - - '='
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.15.2
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 2.9.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.9.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: bahia
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 0.7.2
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.7.2
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 0.9.2.2
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
44
92
  - !ruby/object:Gem::Version
45
- version: 0.14.6
93
+ version: 0.9.2.2
46
94
  description: A Vagrant-like command line interface for creating, managing, and using
47
- EC2 instances for remote pairing.
95
+ EC2 instances for remote pairing like we do at Relevance.
48
96
  email:
49
97
  - larry@hickorywind.org
50
98
  executables:
@@ -61,6 +109,8 @@ files:
61
109
  - lib/pairhost.rb
62
110
  - lib/pairhost/version.rb
63
111
  - pairhost.gemspec
112
+ - spec/pairhost_spec.rb
113
+ - spec/spec_helper.rb
64
114
  - update-nx.sh
65
115
  homepage: http://www.github.com/karnowski/pairhost
66
116
  licenses: []
@@ -85,5 +135,7 @@ rubyforge_project:
85
135
  rubygems_version: 1.8.21
86
136
  signing_key:
87
137
  specification_version: 3
88
- summary: Automate creation of Relevance pairhost EC2 instances.
89
- test_files: []
138
+ summary: Automate creation of Relevance-style pairhost EC2 instances.
139
+ test_files:
140
+ - spec/pairhost_spec.rb
141
+ - spec/spec_helper.rb