Permalink
Browse files

! Added a binary profitbricks to use the API from the command line

  • Loading branch information...
1 parent ce2573b commit fbc2745b602b4ff0a1baf8be315b1b45c5e43aa4 @dsander dsander committed Apr 11, 2012
Showing with 195 additions and 2 deletions.
  1. +17 −1 README.md
  2. +5 −1 bin/profitbricks
  3. +107 −0 lib/profitbricks/cli.rb
  4. +66 −0 spec/profitbricks/cli_spec.rb
View
18 README.md
@@ -29,7 +29,7 @@ Get a list of all your Datacenters
Create a new Datacenter
- dc = DataCenter.create('Name')
+ dc = DataCenter.create(:name => 'Name')
Find a Datacenter by name
@@ -45,6 +45,22 @@ or
Check out the examples directory for more detailed usage information, or have a look at the [documentation](http://rubydoc.info/github/dsander/profitbricks/master/frames) for the class reference.
+## CLI
+
+To use the profitbricks binary you first have to store your username and password in environment variables
+
+ export PROFITBRICKS_USER=yourusername
+ export PROFITBRICKS_PASSWORD=yourpassword
+
+The binary always takes at least two arguments. The first represents a class name (in snake- or camel-case) and the second a method name of this class.
+Get a list of all your datacenters:
+
+ profitbricks data_center all
+
+The following arguments are coverted into a Hash and passed to the method, if you want to call instance methods you _have_ to provide the id of the Server/DataCenter, etc:
+
+ profitbricks server update id=03h17g46-3040-d1af-bb01-9579fe0300e7 cores=2 ram=1024
+
## License
(The MIT License)
View
6 bin/profitbricks
@@ -1,3 +1,7 @@
#!/usr/bin/env ruby
-abort "you need to write me"
+require 'profitbricks'
+require 'profitbricks/cli'
+
+cli = Profitbricks::CLI.new()
+exit cli.run(ARGV)
View
107 lib/profitbricks/cli.rb
@@ -0,0 +1,107 @@
+require 'optparse'
+require 'pp'
+
+module Profitbricks
+ class CLI
+ attr_accessor :stdout
+
+ def initialize(stdout = $stdout)
+ @options = {:debug => false}
+ @stdout = stdout
+ end
+
+ def run(options)
+ options = OptionParser.new do |opts|
+ opts.banner = "Usage: profitbricks [options] <class> <method> argument=value argument2=value2 .."
+ opts.separator ""
+ opts.separator "You have to supply your Profitbricks user name and password in the environmental variables PROFITBRICKS_USER and PROFITBRICKS_PASSWORD"
+ opts.separator ""
+ opts.on("-d", "--debug", "Enable debugging output") do |d|
+ @options[:debug] = d
+ end
+ opts.on_tail("-h", "--help", "Show this message") do
+ @stdout.puts opts
+ return -1
+ end
+ if !ENV['PROFITBRICKS_USER'] or !ENV['PROFITBRICKS_PASSWORD'] or options.length < 2
+ @stdout.puts opts
+ return -1
+ end
+
+ end.parse!(options)
+
+ Profitbricks.configure do |config|
+ config.username = ENV['PROFITBRICKS_USER']
+ config.password = ENV['PROFITBRICKS_PASSWORD']
+ config.log = @options[:debug]
+ end
+
+ (klass, m, arguments) = convert_arguments(options)
+
+ begin
+ klass = Profitbricks.get_class(klass)
+ rescue LoadError
+ @stdout.puts "Invalid class name #{klass}."
+ return -1
+ end
+
+ if method = get_singleton_method(klass, m)
+ dump = PP.pp(call_singleton_method(klass, m, arguments), "")
+ @stdout.puts dump
+ elsif method = get_instance_method(klass, m)
+ dump = PP.pp(call_instance_method(klass, m, arguments), "")
+ @stdout.puts dump
+ else
+ @stdout.puts "#{klass} has no method #{m}"
+ return -1
+ end
+ return 0
+ end
+
+
+ def convert_arguments(options)
+ arguments = Hash[options[2..-1].collect { |x|
+ a = x.split('=');
+ a[1] = a[1].to_i if a[1] =~ /^\d+$/
+ [a[0].to_sym, a[1]]
+ }]
+ [options[0], options[1], arguments]
+ end
+
+ def get_singleton_method(klass, method)
+ methods = klass.singleton_methods(false)
+ if methods.collect { |m| m.to_sym }.include?(method.to_sym)
+ return klass.method(method.to_sym)
+ end
+ end
+
+ def get_instance_method(klass, method)
+ obj = klass.send(:new, {})
+ methods = obj.public_methods(false)
+ if methods.collect { |m| m.to_sym }.include?(method.to_sym)
+ return obj.method(method)
+ end
+ end
+
+ def call_singleton_method(klass, method, arguments)
+ call_method(klass, method, arguments)
+ end
+
+ def call_instance_method(klass, method, arguments)
+ id = arguments.delete(:id)
+ obj = klass.send(:find, {:id => id})
+ call_method(obj, method, arguments)
+ end
+
+ def call_method(klass, method, arguments)
+ if arguments.length > 0
+ klass.send(method, arguments)
+ else
+ klass.send(method)
+ end
+ end
+
+ class << self
+ end
+ end
+end
View
66 spec/profitbricks/cli_spec.rb
@@ -0,0 +1,66 @@
+require 'spec_helper'
+require 'profitbricks/cli'
+
+describe Profitbricks::CLI do
+ include Savon::Spec::Macros
+
+ before(:all) do
+ ENV['PROFITBRICKS_USER'] = 'bogus'
+ ENV['PROFITBRICKS_PASSWORD'] = 'bogus'
+ end
+ let(:cli) { Profitbricks::CLI.new(StringIO.new) }
+
+ it "should return with no username and password" do
+ ENV.delete('PROFITBRICKS_USER')
+ cli.run(["data_center", "all"]).should == -1
+ ENV['PROFITBRICKS_USER'] = 'bogus'
+ end
+
+ it "should require at least to arguments" do
+ cli.run(["data_center"]).should == -1
+ end
+
+ it "should display the help message" do
+ cli.run(["-h bogus"]).should == -1
+ end
+
+ it "should abort with a invalid class" do
+ cli.run(%w(bogus fail)).should == -1
+ end
+
+ it "should abort with a invalid method" do
+ cli.run(%w(server fail)).should == -1
+ end
+
+ it "should convert the arguments to a hash" do
+ args = %w(data_center create id=12 name=Test)
+ (klass, m, arguments) = cli.convert_arguments(args)
+ klass.should == "data_center"
+ m.should == "create"
+ arguments.class.should == Hash
+ arguments[:id].should == 12
+ arguments[:name].should == "Test"
+ end
+
+ it "should get a singleton method" do
+ method = cli.get_singleton_method(Profitbricks::DataCenter, 'all')
+ method.should == Profitbricks::DataCenter.method('all')
+ end
+
+ it "should get a instance method" do
+ method = cli.get_instance_method(Profitbricks::Server, 'update')
+ method.to_s.should == Profitbricks::Server.new({}).method('update').to_s
+ end
+
+ it "should get all data centers" do
+ savon.expects(:get_all_data_centers).returns(:test_datacenter)
+ savon.expects(:get_data_center).returns(:two_servers_with_storage)
+ cli.run(%w(data_center all)).should == 0
+ end
+
+ it "should update a server" do
+ savon.expects(:get_server).returns(:after_create)
+ savon.expects(:update_server).returns(:basic)
+ cli.run(%w(server update id=1234-123 name=meme ram=256 cores=1)).should == 0
+ end
+end

0 comments on commit fbc2745

Please sign in to comment.