opsicle 0.0.4 → 0.1.0

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- Y2VhNTY1NzFlMTEwZjllOGE1Y2JmY2JlYWM4ODIyMzFlZDA3MzBmMA==
4
+ MWY2NTQzM2MwYjY3NDE2OGEzOGE4NTk2NDQzZjVkMjhjOGVlOThiZQ==
5
5
  data.tar.gz: !binary |-
6
- YjNjZGFmZmRlZmYyYzgxMTIzYTA2OWM1NzI0YmZjY2ZlYWM4NjQ5OA==
6
+ MjEyZmMwMDZmODBlYTkxOGY1NzcxZWRhNGM4NWZmMzJiYzNmMDEwNA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NDc0OTUxMTNlYWUzMDhiZDRlZTY3ODYzOWNiODliMmU5MGRlNjU1NGNkZDYz
10
- MjI2Yzk3ODVjMmFjMGZiMzFlMjU2MWNkNGFhN2ZiODcxNzcyOTFmZjA2OWZi
11
- MTA2ZmRjOWQ2ODhjYjdiYWZkNjEzY2YyMjc1OTlhMDlkZWI3MTM=
9
+ MTNiYTM1NDY4MTIwYmE2OTA2ZGViOGM1YzMwZWQyZDY1NTQyM2ZhZmE1NjVh
10
+ Mjg5NTg3YzZmYmU3NDcxY2Q5NWE2N2MyYWE0YzkwN2I2YzVkZGVmNmMwMzk3
11
+ NWU3ZTdiMTBiMzI3Zjc2ZGUwMTBkYzRjYzMzZTNjYThjNTdlNTY=
12
12
  data.tar.gz: !binary |-
13
- ZmI2ZmYxN2ViYmEyYmFjNTEwMjI1ZTEzNWUwYWZlODBhZWVmMzBmNzUzNWJm
14
- NDYzYWU2MDg4MDAxYzBkNzNmYWQ2YTU4MjE3MjgwMTViNThhZmUyMjZjMWE4
15
- MDE4MGEyNzdjN2NhZWQxZTZiYzNjZDkxNTQ2YzhkY2IyNThmMjY=
13
+ NzQyMTc1ZDI3NjMwNGRiMWQ4NjhlNzVjMjE0MjI4MzU4OWZiNTFiNmZmYWNm
14
+ OGZkOTYzYWJiMWQ3NWVkMDY3MTVmYWUzODRiYWJjNzM3YjM3ZDk3Mzc4MmY4
15
+ NjhjNjQ3OWY5ZTQ0NDE2N2FhYjE1OWYyNjg3YzQ4ZjUyMGEwN2E=
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.0
4
+ - 2.1
4
5
  - 1.9.3
5
6
  - jruby-19mode # JRuby in 1.9 mode
6
- - rbx-2.1.1
7
7
  script: bundle exec rspec
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- opsicle (0.0.4)
4
+ opsicle (0.1.0)
5
5
  aws-sdk (~> 1.30)
6
6
  commander
7
7
  terminal-table
@@ -1,8 +1,11 @@
1
- Opsworks CLI - opsicle
2
- ---------------------
1
+ #Opsicle, an OpsWorks CLI
2
+ A gem bringing the glory of OpsWorks to your command line.
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/opsicle.png)](http://badge.fury.io/rb/opsicle)
5
+ [![Build Status](https://travis-ci.org/sportngin/opsicle.png?branch=master)](https://travis-ci.org/sportngin/opsicle)
6
+
7
+ ##Deployment Commands
3
8
 
4
- Deployment Commands
5
- --------------
6
9
  ```bash
7
10
  # Run a basic deploy for the current app
8
11
  opsicle deploy staging
@@ -10,18 +13,20 @@ opsicle deploy staging
10
13
  # Run the deploy for production
11
14
  opsicle deploy production
12
15
 
13
- ```
16
+ # SSH to a server instance in the given environment stack (ex: staging)
17
+ opsicle ssh staging
14
18
 
15
- ```bash
16
19
  # Run other opsworks commands
17
20
  opsicle update_custom_cookbooks staging
18
21
 
19
22
  # Trigger the setup event
20
23
  opsicle setup staging
21
- ````
24
+ ```
25
+
26
+ Opsicle accepts a `--verbose` flag to show additional information as commands are run.
27
+
28
+ ##Set up an Application to use opsicle
22
29
 
23
- Setup an Application to use opsicle
24
- -------
25
30
  ```yaml
26
31
  # your_app_root/.opsicle
27
32
 
@@ -9,23 +9,34 @@ program :version, Opsicle::VERSION
9
9
  program :description, 'Opsworks Command Line Utility Belt'
10
10
  program :help, 'Documentation', 'For documentation and help in setting up your configuration files, '\
11
11
  'see Opsicle\'s GitHub repo: https://github.com/sportngin/opsicle'
12
+
13
+ global_option '--verbose'
14
+
12
15
  default_command :help
13
16
 
14
17
  command :deploy do |c|
15
18
  c.syntax = "opsicle deploy <environment>"
16
- c.description = "Deploy Your current app to the given Opswork Stack"
19
+ c.description = "Deploy your current app to the given OpsWorks stack"
17
20
  c.action do |args, options|
18
21
  raise ArgumentError, "Environment is required" unless args.first
19
- Opsicle::Deploy.new(args.first).execute
22
+ Opsicle::Deploy.new(args.first).execute(options.__hash__)
20
23
  end
21
24
  end
22
25
 
23
26
  command :list do |c|
24
27
  c.syntax = "opsicle list <environment>"
25
- c.description = "List all apps the given environment"
28
+ c.description = "List all apps in the given environment"
26
29
  c.action do |args, options|
27
30
  raise ArgumentError, "Environment is required" unless args.first
28
- Opsicle::List.new(args.first).execute
31
+ Opsicle::List.new(args.first).execute(options.__hash__)
29
32
  end
33
+ end
30
34
 
35
+ command :ssh do |c|
36
+ c.syntax = "opsicle ssh <environment>"
37
+ c.description = "SSH access to instances in the given Opsworks stack"
38
+ c.action do |args, options|
39
+ raise ArgumentError, "Environment is required" unless args.first
40
+ Opsicle::SSH.new(args.first).execute(options.__hash__)
41
+ end
31
42
  end
@@ -1,4 +1,11 @@
1
+ Signal.trap("INT") do
2
+ puts ""
3
+ puts "Exiting..."
4
+ exit 1
5
+ end
6
+
1
7
  require "opsicle/version"
2
8
  require "opsicle/deploy"
3
9
  require "opsicle/list"
10
+ require "opsicle/ssh"
4
11
 
@@ -16,7 +16,7 @@ module Opsicle
16
16
  end
17
17
 
18
18
  def api_call(command, options={})
19
- aws_client.send(command, options)
19
+ aws_client.public_send(command, options)
20
20
  end
21
21
 
22
22
  def command_options(command, options={})
@@ -28,7 +28,10 @@ module Opsicle
28
28
 
29
29
  def load_config(file)
30
30
  raise MissingConfig, "Missing configuration file: #{file} Run 'opsicle help'" unless File.exist?(file)
31
- symbolize_keys(YAML.load_file(file))[environment] rescue {}
31
+ env_config = symbolize_keys(YAML.load_file(file))[environment] rescue {}
32
+ raise MissingEnvironment, "Configuration for the \'#{environment}\' environment could not be found in #{file}" unless env_config != nil
33
+
34
+ env_config
32
35
  end
33
36
 
34
37
  # We want all ouf our YAML loaded keys to be symbols
@@ -49,6 +52,7 @@ module Opsicle
49
52
  end
50
53
 
51
54
  MissingConfig = Class.new(StandardError)
55
+ MissingEnvironment = Class.new(StandardError)
52
56
 
53
57
  end
54
58
  end
@@ -9,7 +9,7 @@ module Opsicle
9
9
  @client = Client.new(environment)
10
10
  end
11
11
 
12
- def execute
12
+ def execute(options={})
13
13
  response = client.run_command('deploy')
14
14
  open_deploy(response[:deployment_id])
15
15
  end
@@ -10,7 +10,7 @@ module Opsicle
10
10
  @client = Client.new(environment)
11
11
  end
12
12
 
13
- def execute
13
+ def execute(options={})
14
14
  stack_ids = get_stacks
15
15
  apps = get_apps(stack_ids)
16
16
  print(apps)
@@ -0,0 +1,39 @@
1
+ require 'aws-sdk'
2
+ require_relative 'client'
3
+
4
+ module Opsicle
5
+ class SSH
6
+ attr_reader :client
7
+
8
+ def initialize(environment)
9
+ @client = Client.new(environment)
10
+ end
11
+
12
+ def execute(options={})
13
+ if instances.length == 1
14
+ choice = 1
15
+ else
16
+ say "Choose an Opsworks instance: \n"
17
+ instances.each_index do |x|
18
+ say "#{x+1}) #{instances[x][:hostname]}"
19
+ end
20
+ choice = ask("? ", Integer) { |q| q.in = 1..instances.length }
21
+ end
22
+
23
+ instance_ip = instances[choice-1][:elastic_ip] || instances[choice-1][:public_ip]
24
+
25
+ command = "ssh #{ssh_username}@#{instance_ip}"
26
+ say "<%= color('Executing shell command: #{command}', YELLOW) %>" if options[:verbose] == true
27
+ system(command)
28
+ end
29
+
30
+ def instances
31
+ client.api_call(:describe_instances, { stack_id: client.config.opsworks_config[:stack_id] })
32
+ .data[:instances]
33
+ end
34
+
35
+ def ssh_username
36
+ client.api_call(:describe_my_user_profile)[:user_profile][:ssh_username]
37
+ end
38
+ end
39
+ end
@@ -1,3 +1,3 @@
1
1
  module Opsicle
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,86 @@
1
+ require "spec_helper"
2
+ require "opsicle/ssh"
3
+
4
+ module Opsicle
5
+ describe SSH do
6
+ subject { SSH.new('derp') }
7
+ let(:client) { double(config: double(opsworks_config: {stack_id: "1234"})) }
8
+ let(:api_call) { double }
9
+ before do
10
+ Client.stub(:new).with('derp').and_return(client)
11
+ end
12
+
13
+ context "#execute" do
14
+ before do
15
+ subject.stub(:say) { "What instance do you want, huh?" }
16
+ subject.stub(:ask).and_return(2)
17
+ subject.stub(:ssh_username) {"mrderpyman2014"}
18
+ end
19
+
20
+ it "should execute ssh with a selected Opsworks instance IP" do
21
+ subject.stub(:instances) {[
22
+ { hostname: "host1", elastic_ip: "123.123.123.123" },
23
+ { hostname: "host2", elastic_ip: "789.789.789.789" }
24
+ ]}
25
+
26
+ subject.should_receive(:system).with("ssh mrderpyman2014@789.789.789.789")
27
+ subject.execute
28
+ end
29
+
30
+ it "should execute ssh with public_ip listings as well as elastic_ip" do
31
+ subject.stub(:instances) {[
32
+ { hostname: "host1", elastic_ip: "678.678.678.678" },
33
+ { hostname: "host2", public_ip: "987.987.987.987" }
34
+ ]}
35
+
36
+ subject.should_receive(:system).with("ssh mrderpyman2014@987.987.987.987")
37
+ subject.execute
38
+ end
39
+
40
+ it "should execute ssh favoring an elastic_ip over a public_ip if both exist" do
41
+ subject.stub(:instances) {[
42
+ { hostname: "host1", elastic_ip: "678.678.678.678" },
43
+ { hostname: "host2", public_ip: "987.987.987.987", elastic_ip: "132.132.132.132" }
44
+ ]}
45
+
46
+ subject.should_receive(:system).with("ssh mrderpyman2014@132.132.132.132")
47
+ subject.execute
48
+ end
49
+
50
+ it "should execute ssh right away if there is only one Opsworks instance available" do
51
+ subject.stub(:instances) {[
52
+ { hostname: "host3", elastic_ip: "456.456.456.456" }
53
+ ]}
54
+
55
+ subject.should_receive(:system).with("ssh mrderpyman2014@456.456.456.456")
56
+ subject.should_not_receive(:ask)
57
+ subject.execute
58
+ end
59
+ end
60
+
61
+ context "#client" do
62
+ it "generates a new aws client from the given configs" do
63
+ Client.should_receive(:new).with('derp')
64
+ subject.client
65
+ end
66
+ end
67
+
68
+ context "#instances" do
69
+ it "makes a describe_instances API call" do
70
+ client.stub(:api_call).with(:describe_instances, {stack_id: "1234"})
71
+ .and_return(api_call)
72
+ api_call.should_receive(:data).and_return(instances: {:foo => :bar})
73
+ subject.instances.should == {:foo => :bar}
74
+ end
75
+ end
76
+
77
+ context "#ssh_username" do
78
+ it "makes a describe_my_user_profile API call" do
79
+ client.stub(:api_call).with(:describe_my_user_profile)
80
+ .and_return({user_profile: {:ssh_username => "captkirk01"}})
81
+ subject.ssh_username.should == "captkirk01"
82
+ end
83
+ end
84
+
85
+ end
86
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opsicle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Fleener
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-31 00:00:00.000000000 Z
11
+ date: 2014-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -146,12 +146,14 @@ files:
146
146
  - lib/opsicle/config.rb
147
147
  - lib/opsicle/deploy.rb
148
148
  - lib/opsicle/list.rb
149
+ - lib/opsicle/ssh.rb
149
150
  - lib/opsicle/version.rb
150
151
  - opsicle.gemspec
151
152
  - spec/opsicle/client_spec.rb
152
153
  - spec/opsicle/config_spec.rb
153
154
  - spec/opsicle/deploy_spec.rb
154
155
  - spec/opsicle/list_spec.rb
156
+ - spec/opsicle/ssh_spec.rb
155
157
  - spec/spec_helper.rb
156
158
  homepage: https://github.com/sportngin/opsicle
157
159
  licenses:
@@ -182,4 +184,5 @@ test_files:
182
184
  - spec/opsicle/config_spec.rb
183
185
  - spec/opsicle/deploy_spec.rb
184
186
  - spec/opsicle/list_spec.rb
187
+ - spec/opsicle/ssh_spec.rb
185
188
  - spec/spec_helper.rb