Permalink
Browse files

Initial commit: working 'servers' method

  • Loading branch information...
0 parents commit 7ce15b1d7fb352eb4718b939e53ed14dfcde4932 @joeyates committed Sep 28, 2010
Showing with 261 additions and 0 deletions.
  1. +20 −0 COPYING
  2. +42 −0 README.rdoc
  3. +44 −0 Rakefile
  4. +155 −0 lib/rightscale.rb
@@ -0,0 +1,20 @@
+Copyright (c) 2010 Joe Yates
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,42 @@
+= rightstuff - Another Ruby Interface for RightScale
+
+Here is a typical example:
+
+ require 'rubygems' if RUBY_VERSION < '1.9'
+ require 'rightstuff'
+
+ include Rightstuff::Credentials
+
+ rs = Rightstuff::Client.new( rightscale_data[ :main ][ :credentials ] )
+ servers = rs.servers
+ servers.each{ |server| puts server.private_ip_address }
+
+Rightstuff::Credentials assumes you have a YAMl file called ~/.rightstuff
+It should be of the form:
+ ---
+ :main:
+ :credentials:
+ :username: myusername
+ :password: mypass
+ :account: 1234
+
+= Installation
+
+ $ sudo gem install rightstuff
+
+= Online
+
+* {Source code}[http://github.com/joeyates/rightstuff]
+* Documentation[http://rdoc.info/projects/joeyates/rightstuff]
+* Gem[http://rubygems.org/gems/rightstuff]
+
+= Alternatives
+
+* http://github.com/rightscale/right_link - RightScale's messaging API for live servers
+* http://github.com/rightscale/right_aws
+* http://github.com/moneypools/right_api
+
+= TODO
+
+* Cache connections
+* Don't query inactive serevrs for settings
@@ -0,0 +1,44 @@
+require 'rubygems' if RUBY_VERSION < '1.9'
+require 'rake'
+require 'rake/gempackagetask'
+require 'rake/rdoctask'
+$:.unshift( File.dirname( __FILE__ ) + '/lib' )
+require 'rightstuff'
+
+ADMIN_FILES = FileList[ 'COPYING', 'Rakefile', 'README.rdoc' ]
+SOURCE_FILES = FileList[ 'lib/**/*.rb' ]
+RDOC_FILES = FileList[ 'COPYING', 'README.rdoc' ] + SOURCE_FILES
+RDOC_OPTS = [ '--quiet', '--main', 'README.rdoc', '--inline-source' ]
+DESCRIPTION = 'Another Ruby Interface for RightScale, providing an OO interface for RightScale accounts'
+
+spec = Gem::Specification.new do |s|
+ s.name = 'rightstuff'
+ s.summary = 'Another Ruby Interface for RightScale'
+ s.description = DESCRIPTION
+ s.version = Rightstuff::VERSION::STRING
+
+ s.homepage = 'http://github.com/joeyates/rightstuff'
+ s.author = 'Joe Yates'
+ s.email = 'joe.g.yates@gmail.com'
+
+ s.files = ADMIN_FILES +
+ SOURCE_FILES
+ s.require_paths = [ 'lib' ]
+ s.add_dependency( 'nokogiri', '>= 1.4.3.1' )
+
+ s.has_rdoc = true
+ s.rdoc_options += RDOC_OPTS
+ s.extra_rdoc_files = RDOC_FILES
+
+ s.test_files = SPEC_FILES
+end
+
+Rake::GemPackageTask.new( spec ) do |pkg|
+end
+
+Rake::RDocTask.new do |rdoc|
+ rdoc.rdoc_dir = 'html'
+ rdoc.options += RDOC_OPTS
+ rdoc.title = DESCRIPTION
+ rdoc.rdoc_files.add RDOC_FILES
+end
@@ -0,0 +1,155 @@
+#!ruby
+
+require 'rubygems' if RUBY_VERSION < '1.9'
+require 'yaml'
+require 'net/https'
+require 'uri'
+require 'nokogiri'
+
+module Rightstuff
+
+ module VERSION #:nodoc:
+ MAJOR = 0
+ MINOR = 0
+ TINY = 1
+
+ STRING = [ MAJOR, MINOR, TINY ].join('.')
+ end
+
+ module Credentials
+
+ def rightscale_data_path
+ File.expand_path( '~/.rightscale' )
+ end
+
+ def check_permissions
+ mode = File::Stat.new( rightscale_data_path ).mode
+ if mode & 0066 != 0
+ raise "Permissions on '#{ rightscale_data_path }' too open (currently 0%o), should be 0600" % ( mode & 0666 )
+ end
+ end
+
+ def rightscale_data
+ return @rightscale_data if @rightscale_data
+ raise "Missing credentials file '#{ rightscale_data_path }'" if ! File.exist?( rightscale_data_path )
+ check_permissions
+ @rightscale_data = YAML.load_file( rightscale_data_path )
+ end
+
+ end
+
+ class Base
+
+ def self.load_collection( client, doc )
+ doc.xpath( self.collection_xpath ).collect do | item |
+ self.new( client, item )
+ end
+ end
+
+ def self.extract_attributes( parent )
+ elements = parent.children.collect do | node |
+ node.class == Nokogiri::XML::Element ? node : nil
+ end
+ elements.compact!
+ elements.reduce({}) do | memo, element |
+ name = element.name
+ name.gsub!( /-/, '_' )
+ memo[ name.intern ] = element.children[0].to_s
+ memo
+ end
+ end
+
+ def initialize( client, item )
+ @client = client
+ @attributes = Base.extract_attributes( item )
+ end
+
+ def method_missing( name, *args, &block )
+ return @attributes[ name ]
+ end
+
+ end
+
+ class Server < Base
+
+ def initialize( client, item )
+ @settings = false
+ super
+ end
+
+ def self.collection_xpath
+ '/servers/server'
+ end
+
+ def method_missing( name , *args, &block )
+ result = super
+ return result unless result.nil?
+ settings unless @settings
+ return @attributes[ name ]
+ end
+
+ def id
+ @attributes[ :href ].split( '/' ).last
+ end
+
+ def inputs
+ # Add inputs to instance data
+ # @client.get( @attributes[ 'href' ] )
+ end
+
+ def settings
+ doc = @client.get_rest( 'servers/' + id + '/settings' )
+ xml = Nokogiri::XML( doc )
+ @attributes.merge!( Base.extract_attributes( xml.children ) )
+ @settings = true
+ end
+
+ end
+
+ class Client
+
+ def initialize( options = {} )
+ @base_url = 'https://my.rightscale.com/api/acct'
+ @username = options[ :username ] or raise 'no username supplied'
+ @password = options[ :password ] or raise 'no password supplied'
+ @account = options[ :account ] or raise 'no account id supplied'
+ @account = @account.to_s
+ end
+
+ def get_rest( rest )
+ get( account_url( rest ) )
+ end
+
+ def get( path )
+ address = path
+ url = URI.parse( address )
+ con = Net::HTTP.new( url.host, url.port )
+ con.use_ssl = true
+ con.verify_mode = OpenSSL::SSL::VERIFY_NONE
+
+ request = Net::HTTP::Get.new( url.request_uri )
+ request.add_field( 'X-API-VERSION', '1.0' )
+ request.basic_auth @username, @password
+
+ response = con.request( request )
+
+ case response.code
+ when '200'
+ return response.body
+ else
+ raise "Request '#{ address }' failed with response code #{ response.code }\n#{ response.body }"
+ end
+ end
+
+ def servers
+ body = Nokogiri::XML( get_rest( 'servers' ) )
+ Server.load_collection( self, body )
+ end
+
+ def account_url( rest )
+ @base_url + '/' + @account + '/' + rest
+ end
+
+ end
+
+end

0 comments on commit 7ce15b1

Please sign in to comment.