deltacloud-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mfoj...@redhat.com
Subject [PATCH core] Client: Retired deltacloudc into clients directory
Date Tue, 07 Aug 2012 09:21:57 GMT
From: Michal Fojtik <mfojtik@redhat.com>


Signed-off-by: Michal fojtik <mfojtik@redhat.com>
---
 client/bin/deltacloudc             |  245 ------------------------------------
 client/lib/plain_formatter.rb      |  145 ---------------------
 client/tests/cmd.rb                |  214 -------------------------------
 client/tests/common.rb             |   42 -------
 clients/console/deltacloudc        |  245 ++++++++++++++++++++++++++++++++++++
 clients/console/plain_formatter.rb |  145 +++++++++++++++++++++
 clients/console/tests/cmd.rb       |  214 +++++++++++++++++++++++++++++++
 clients/console/tests/common.rb    |   42 +++++++
 8 files changed, 646 insertions(+), 646 deletions(-)
 delete mode 100755 client/bin/deltacloudc
 delete mode 100644 client/lib/plain_formatter.rb
 delete mode 100644 client/tests/cmd.rb
 delete mode 100644 client/tests/common.rb
 create mode 100755 clients/console/deltacloudc
 create mode 100644 clients/console/plain_formatter.rb
 create mode 100644 clients/console/tests/cmd.rb
 create mode 100644 clients/console/tests/common.rb

diff --git a/client/bin/deltacloudc b/client/bin/deltacloudc
deleted file mode 100755
index adc5d11..0000000
--- a/client/bin/deltacloudc
+++ /dev/null
@@ -1,245 +0,0 @@
-#!/usr/bin/env ruby
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'rubygems'
-require 'optparse'
-require 'uri'
-require 'deltacloud'
-require 'plain_formatter'
-
-include DeltaCloud::PlainFormatter
-
-options = {
-  :verbose => false
-}
-
-@optparse = OptionParser.new do |opts|
-
-opts.banner = <<BANNER
-Usage:
-deltacloudc collection operation [options]
-
-URL format:
-API_URL=http://[user]:[password]@[api_url][port][/uri]
-  OR 
-API_URL=http://[api_url][port][/uri] with -U and -P for credentials
-
-Examples:
-
- 1. To list collections for deltacloud api on port 3333 of server deltacloud.foo
-
-        deltacloudc -l -u http://user:password@deltacloud.foo:3333/api
-
- 2. To list the operations for the 'images' collection:
-
-        deltacloudc images -l -U username -P password -u http://deltacloud.foo:3333/api
-
- 3. To list all images (i.e. call the 'index' operation of 'images'):
-
-        deltacloudc images index -u http://user:password@deltacloud.foo:3333/api
-
- 4. To get the details of image '5':
-
-        deltacloudc images show -i 5 -U username -P password -u http://deltacloud.foo:3333/api
-
-Options:
-BANNER
-  opts.on( '-i', '--id ID', 'ID for operation') { |id| options[:id] = id }
-  opts.on( '-d', '--image-id ID', 'Image ID') { |id| options[:image_id] = id }
-  opts.on( '-b', '--bucket-id ID', 'Bucket ID') {|id| options[:bucket_id] = id }
-  opts.on( '-r', '--bucket-location NAME', 'Bucket location') {|name| options[:bucket_location]
= name }
-  opts.on( '-a', '--arch ARCH', 'Architecture (x86, x86_64)') { |id| options[:architecture]
= id }
-  opts.on( '-p', '--hardware-profile HARDWARE_PROFILE', 'Hardware Profile') { |id| options[:hwp_id]
= id }
-  opts.on( '-n', '--name NAME', 'Name (for instance eg.)') { |name| options[:name] = name
}
-  opts.on( '-s', '--state STATE', 'Instance state (RUNNING, STOPPED)') { |state| options[:state]
= state }
-  opts.on( '-u', '--url URL', 'API url ($API_URL variable)') { |url| options[:api_url] =
url }
-  opts.on( '-U', '--user USER', 'API username ($API_USERNAME variable)') { |u| options[:api_user]
= u }
-  opts.on( '-P', '--password PASSWORD', 'API password ($API_PASSWORD variable)') { |p| options[:api_password]
= p }
-  opts.on( '-l', '--list', 'List collections/operations') { |id| options[:list] = true }
-  opts.on( '-h', '--help', 'Display this screen' ) { puts @optparse; Kernel.exit! }
-  opts.on( '-v', '--version', 'Display API version' ) { options[:version]=true }
-  opts.on( '-V', '--verbose', 'Print verbose messages' ) { options[:verbose]=true }
-  opts.on( '-f', '--file-path PATH', 'local path for new blob data') {|path| options[:file_path]=path
}
-  opts.on( '-m', '--blob-metadata k1=v1, k2=v2', 'Comma seperated k=v pairs for blob metadata
(for create operation)') do |meta|
-                    blob_meta = {}
-                    meta.gsub!(/ /,"")
-                    meta.scan(/(\w+)=(\w+)/).map {|k,v| blob_meta[k] = v }
-                    options[:blob_metadata] = blob_meta
-                end
-end
-
-def invalid_usage(error_msg='')
-  puts "\n ERROR: #{error_msg} \n\n"
-  puts @optparse
-  exit(1)
-end
-
-begin
-    @optparse.parse!
-rescue Exception => e
-    invalid_usage(e.message)
-end
-
-# First try to get API_URL from environment
-options[:api_url] = ENV['API_URL'] if options[:api_url].nil?
-
-if(options[:api_url].nil?)
-    invalid_usage("You must supply the url to the deltacloud api; either use '-u' flag or
set the 'API_URL' environment variable")
-end
-
-url = URI.parse(options[:api_url])
-api_url = "http://#{url.host}#{url.port ? ":#{url.port}" : ''}#{url.path}"
-
-options[:collection] = ARGV[0]
-options[:operation] = ARGV[1]
-
-# Connect to Deltacloud API and fetch all entry points
-client = DeltaCloud.new(options[:api_user] || url.user || ENV['API_USER'], options[:api_password]
|| url.password || ENV['API_PASSWORD'], api_url)
-collections = client.entry_points.keys
-
-# Exclude collection which don't have methods in client library yet
-collections.delete(:instance_states)
-#add blob collection if buckets is present
-collections << :blob if collections.include?(:buckets)
-
-# If list parameter passed print out available collection
-# with API documentation
-if options[:list] and options[:collection].nil?
-  collections.each do |c|
-    puts sprintf("%-22s", c.to_s[0, 22])
-  end
-  exit(0)
-end
-
-# If collection parameter is present and user requested list
-# print all operation defined for collection with API documentation
-if options[:list] and options[:collection]
-  #deal with blobs again - bypass 'normal' docs procedure
-  if options[:collection] =~ /blob/i
-    puts "create \t\t: Create a new blob in a specified bucket (POST /api/buckets/:bucket)"
-    puts "destroy \t: Delete a specified blob in a specified bucket (DELETE /api/buckets/:bucket/:blob)"
-    puts "show \t\t: Get details of a specified blob in a specified bucket (GET /api/buckets/:bucket/:blob)"
-    puts "data \t\t: Get the contents of a specified blob - the blob data content itself"
-    exit(0)
-  end
-  doc = client.documentation(options[:collection])
-  doc.operations.each do |c|
-    puts sprintf("%-20s: %s", c.operation, c.description)
-  end
-  exit(0)
-end
-
-if options[:version]
-  puts "Deltacloud API(#{client.driver_name}) 0.1"
-  exit(0)
-end
-
-# List items from collection (typically /instances)
-# Do same if 'index' operation is set
-if options[:collection] and ( options[:operation].nil? or options[:operation].eql?('index')
)
-  invalid_usage("Unknown collection: #{options[:collection]}") unless collections.include?(options[:collection].to_sym)
-#cannot list blobs - can only show a specific blob
-  invalid_usage("You must specify a particular blob with -i and a particular bucket with
-b") if options[:collection] =~ (/blob/i)
-  params = {}
-  params.merge!(:architecture => options[:architecture]) if options[:architecture]
-  params.merge!(:id => options[:id]) if options[:id]
-  params.merge!(:state => options[:state]) if options[:state]
-  client.send(options[:collection].to_s, params).each do |model|
-    puts format(model)
-  end
-  exit(0)
-end
-
-if options[:collection] and options[:operation]
-
-  invalid_usage("Unknown collection: #{options[:collection]}") unless collections.include?(options[:collection].to_sym)
-
-  params = {}
-  params.merge!(:id => options[:id]) if options[:id]
-
-  # If collection is set and requested operation is 'show' just 'singularize'
-  # collection name and print item with specified id (-i parameter)
-  #Blobs are a special case so deal with first -
-  if options[:collection] =~ (/blob/i)
-    invalid_usage("Please specify the bucket for this blob using the -b option") unless options[:bucket_id]
-    invalid_usage("Missing blob ID, please specify with -i option") unless options[:id]
-    params = {}
-    params.merge!(:id => options[:id], 'bucket' => options[:bucket_id])
-    params.merge!('metadata'=>options[:blob_metadata]) unless options[:blob_metadata].nil?
-    case options[:operation]
-        when 'show' then puts format(client.send( options[:collection], params))
-        when 'data' then puts client.blob_data(params)
-        when 'create' then
-            invalid_usage("Specify the location of the new blob data (full local path) using
-f option") unless options[:file_path]
-            params.merge!('file_path'=>options[:file_path])
-            blob = client.create_blob(params)
-            puts format(blob)
-        when 'destroy' then client.destroy_blob(params)
-        else invalid_usage("Please specify a valid operation for the blob collection - try
-l to see available operations")
-    end
-    exit(0)
-  end
-
-  if options[:operation].eql?('show')
-    invalid_usage("Missing ID, must be provided with --id") unless options[:id]
-    puts format(client.send(options[:collection].gsub(/s$/, ''), options[:id]))
-    exit(0)
-  end
-
-  # If collection is set and requested operation is create new instance,
-  # --image-id, --hardware-profile and --name parameters are used
-  # Returns created instance in plain form
-  if options[:collection].eql?('instances') and options[:operation].eql?('create')
-    invalid_usage("Missing image-id") unless options[:image_id]
-    if options[:name] and ! client.feature?(:instances, :user_name)
-      invalid_usage("Driver does not support user-supplied name")
-    end
-    params.merge!(:name => options[:name]) if options[:name]
-    params.merge!(:image_id => options[:image_id]) if options[:image_id]
-    params.merge!(:hwp_id => options[:hwp_id]) if options[:hwp_id]
-    instance = client.create_instance(options[:image_id], params)
-    puts format(instance)
-    exit(0)
-  end
-
-  #Create and Destroy a bucket - require the bucket id:
-  if options[:collection].eql?('buckets')
-    if options[:operation].eql?('create')
-        invalid_usage("Please specify an id for the new bucket with -i") unless options[:id]
-        bucket = client.create_bucket('id'=>options[:id], 'bucket_location'=>options[:bucket_location])
-        puts format(bucket)
-    elsif options[:operation].eql?('destroy')
-        invalid_usage("Please specify the bucket you wish to destroy with -i") unless options[:id]
-        client.destroy_bucket('id'=>options[:id])
-    else
-        invalid_usage("Please specify a valid operation on buckets - use -l to see valid
operations")
-    end
-    exit(0)
-  end
-
-  # All other operations above collections is done there:
-  if options[:collection].eql?('instances')
-    instance = client.instance(options[:id])
-    instance.send("#{options[:operation]}!".to_s)
-    instance = client.instance(options[:id])
-    puts format(instance)
-    exit(0)
-  end
-end
-
-# If all above passed (eg. no parameters)
-puts @optparse
diff --git a/client/lib/plain_formatter.rb b/client/lib/plain_formatter.rb
deleted file mode 100644
index 2e2ada3..0000000
--- a/client/lib/plain_formatter.rb
+++ /dev/null
@@ -1,145 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module DeltaCloud
-  module PlainFormatter
-    module FormatObject
-
-      class Base
-        def initialize(obj)
-          @obj = obj
-        end
-      end
-
-      class Key < Base
-        def format
-          sprintf("%-10s | %-60s",
-              @obj.id[0,10],
-              @obj.fingerprint
-          )
-        end
-      end
-
-      class Image < Base
-        def format
-          sprintf("%-10s | %-20s | %-6s | %-20s | %15s",
-              @obj.id[0,10],
-              @obj.name ? @obj.name[0, 20]: 'unknown',
-              @obj.architecture[0,6],
-              @obj.description[0,20],
-              @obj.owner_id[0,15]
-          )
-        end
-      end
-
-      class Realm < Base
-        def format
-          sprintf("%-10s | %-15s | %-5s | %10s GB",
-            @obj.id[0, 10],
-            @obj.name[0, 15],
-            @obj.state[0,5],
-            @obj.limit.to_s[0,10]
-          )
-        end
-      end
-
-      class HardwareProfile < Base
-        def format
-          architecture = @obj.architecture ? @obj.architecture.value[0,6] : 'opaque'
-          memory = @obj.memory ? @obj.memory.value.to_s[0,10] : 'opaque'
-          storage = @obj.storage ? @obj.storage.value.to_s[0,10] : 'opaque'
-          sprintf("%-15s | %-6s | %10s | %10s ", @obj.id[0, 15],
-           architecture , memory, storage)
-        end
-      end
-
-      class Instance < Base
-        def format
-          sprintf("%-15s | %-15s | %-15s | %10s | %32s | %32s",
-            @obj.id ? @obj.id.to_s[0,15] : '-',
-            @obj.name ? @obj.name.to_s[0,15] : 'unknown',
-            @obj.image.name ? @obj.image.name.to_s[0,15] : 'unknown',
-            @obj.state ? @obj.state.to_s[0,10] : 'unknown',
-            @obj.public_addresses.collect { |a| a[:address] }.join(',')[0,32],
-            @obj.private_addresses.collect { |a| a[:address] }.join(',')[0,32]
-          )
-        end
-      end
-
-      class StorageVolume < Base
-        def format
-          sprintf("%-10s | %15s GB | %-10s | %-10s | %-15s",
-            @obj.id[0,10],
-            @obj.capacity ? @obj.capacity.to_s[0,15] : 'unknown',
-            @obj.device ? @obj.device[0,10] : 'unknown',
-            @obj.respond_to?('state') ? @obj.state[0,10] : 'unknown',
-            @obj.instance ? @obj.instance.name[0,15] : 'unknown'
-          )
-        end
-      end
-
-      class StorageSnapshot < Base
-        def format
-          sprintf("%-10s | %-15s | %-6s | %15s",
-            @obj.id[0,10],
-            @obj.storage_volume.respond_to?('name') ? @obj.storage_volume.name[0, 15] : 'unknown',
-            @obj.state ? @obj.state[0,10] : 'unknown',
-            @obj.created ? @obj.created[0,19] : 'unknown'
-          )
-        end
-      end
-
-      class Bucket < Base
-        def format
-          sprintf("%-s | %-s | %-s | %-s",
-          @obj.id,
-          @obj.name,
-          @obj.size ? @obj.size : "0",
-          @obj.instance_variables.include?("@blob_list") ? @obj.blob_list : ""
-          )
-        end
-      end
-
-      class Blob < Base
-        def format
-          sprintf("%-s | %-s | %-d | %-s | %-s | %-s " ,
-          @obj.id,
-          @obj.bucket,
-          @obj.content_length,
-          @obj.content_type,
-          @obj.last_modified,
-          @obj.user_metadata
-          )
-        end
-      end
-
-      class Driver < Base
-        def format
-          sprintf("%-15s | %-15s | %-s",
-                  @obj.id,
-                  @obj.name,
-                  @obj.url)
-        end
-      end
-    end
-
-    def format(obj)
-      object_name = obj.class.name.classify.gsub(/^DeltaCloud::API::(\w+)::/, '')
-      format_class = DeltaCloud::PlainFormatter::FormatObject.const_get(object_name)
-      format_class.new(obj).format
-    end
-
-  end
-end
diff --git a/client/tests/cmd.rb b/client/tests/cmd.rb
deleted file mode 100644
index 90fb853..0000000
--- a/client/tests/cmd.rb
+++ /dev/null
@@ -1,214 +0,0 @@
-# Copyright (C) 2009-2011  Red Hat, Inc.
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-require 'rubygems'
-require 'shoulda'
-require 'tests/common'
-
-include DeltaCloud::TestHelper
-
-class CommandLineTest < Test::Unit::TestCase
-  context "a command line client" do
-
-    should "respond to --help argument" do
-      assert_nothing_raised do
-        base_client('--help')
-      end
-    end
-
-    should "return API version with --version argument" do
-      assert_match /Deltacloud API\(mock\) (\d+)\.(\d+)/, client('--version')
-    end
-
-    should "return list all collections with --list argument" do
-      output = nil
-      assert_nothing_raised do
-        output = client('--list')
-      end
-      assert_not_nil output
-      assert_match /images/, output
-      assert_match /instances/, output
-      assert_match /realms/, output
-      assert_match /hardware_profiles/, output
-    end
-
-    should 'respond with proper error when accessing unknow collection' do
-      output = client('unknown_collection')
-      assert_match /ERROR: Unknown collection:/, output
-    end
-
-  end
-end
-
-class CmdRealmTest < Test::Unit::TestCase
-  context "a realms" do
-
-    should "be listed using realms argument" do
-      output = nil
-      assert_nothing_raised do
-        output = client('realms')
-      end
-      assert_match /^us/m, output
-      assert_match /^eu/m, output
-    end
-
-    should "be filtered using show --id argument" do
-      output = nil
-      assert_nothing_raised do
-        output = client('realms show --id us')
-      end
-      assert_match /^us/, output
-      assert_no_match /^eu/, output
-    end
-
-  end
-end
-
-class CmdHardwareProfilesTest < Test::Unit::TestCase
-  context "a hardware profiles" do
-
-    should "be listed using hardware_profiles argument" do
-      output = nil
-      assert_nothing_raised do
-        output = client('hardware_profiles')
-      end
-      assert_no_warning output
-      assert_match /^m1-small/m, output
-      assert_match /^m1-large/m, output
-      assert_match /^m1-xlarge/m, output
-      assert_match /^opaque/m, output
-    end
-
-    should "be filtered using show --id argument" do
-      output = nil
-      assert_nothing_raised do
-        output = client('hardware_profiles show --id m1-large')
-      end
-      assert_no_warning output
-      assert_match /^m1-large/, output
-      assert_no_match /^m1-small/, output
-    end
-  end
-end
-
-class CmdImagesTest < Test::Unit::TestCase
-
-  context "a images" do
-
-    should "be listed using images argument" do
-      output = nil
-      assert_nothing_raised do
-        output = client('images')
-      end
-      assert_no_warning output
-      assert_match /^img2/m, output
-      assert_match /^img1/m, output
-      assert_match /^img3/m, output
-    end
-
-    should "be filtered using show --id argument" do
-      output = nil
-      assert_nothing_raised do
-        output = client('images show --id img2')
-      end
-      assert_no_warning output
-      assert_match /^img2/m, output
-      assert_no_match /^img1/m, output
-    end
-
-    should "be filtered using --arch argument" do
-      output = nil
-      assert_nothing_raised do
-        output = client('images --arch x86_64')
-      end
-      assert_no_warning output
-      assert_match /x86_64/, output
-      assert_no_match /i386/, output
-    end
-
-  end
-
-end
-
-class CmdInstancesTest < Test::Unit::TestCase
-
-  context 'an instances' do
-
-    should 'be listed using instances argument' do
-      output = nil
-      assert_nothing_raised do
-        output = client('instances')
-      end
-      assert_no_warning output
-      assert_match /^inst1/, output
-    end
-
-    should 'be filtered using --id argument' do
-      output = nil
-      assert_nothing_raised do
-        output = client('instances show --id inst0')
-      end
-      assert_no_warning output
-      assert_match /^inst0/m, output
-      assert_no_match /^inst1/m, output
-    end
-
-  end
-
-  context 'an instance' do
-
-    should 'be created supplying --image-id argument and -p argument' do
-      output = nil
-      assert_nothing_raised do
-        output = client('instances create --image-id img1 -p m1-small')
-      end
-      assert_no_warning output
-      assert_match /^inst(\d+)/, output
-      @@created_instance_id = output.match(/^inst(\d+)/).to_a.first
-    end
-
-    should 'be rebooted using reboot operation' do
-      output = nil
-      assert_nothing_raised do
-        output = client("instances reboot --id #{@@created_instance_id}")
-      end
-      assert_no_warning output
-      assert_match /#{@@created_instance_id}/, output
-      assert_match /RUNNING/, output
-    end
-
-    should 'be stopped using stop operation' do
-      output = nil
-      assert_nothing_raised do
-        output = client("instances stop --id #{@@created_instance_id}")
-      end
-      assert_no_warning output
-      assert_match /#{@@created_instance_id}/, output
-      assert_match /STOPPED/, output
-    end
-
-    should 'be destroyed using destroy operation' do
-      output = nil
-      assert_nothing_raised do
-        output = client("instances destroy --id #{@@created_instance_id}")
-      end
-      assert_no_warning output
-    end
-
-  end
-end
diff --git a/client/tests/common.rb b/client/tests/common.rb
deleted file mode 100644
index dc5b475..0000000
--- a/client/tests/common.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2009-2011  Red Hat, Inc.
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-module DeltaCloud
-  module TestHelper
-
-    include Test::Unit::Assertions
-
-    API_URL   = "http://localhost:3001/api"
-    API_USER  = "mockuser"
-    API_PASWD = "mockpassword"
-
-    def base_client(args)
-      `bin/deltacloudc #{args}`
-    end
-
-    def client(args)
-      args = "-u http://mockuser:mockpassword@localhost:3001/api " + args
-      base_client(args)
-    end
-
-    def assert_no_warning(output)
-      assert_no_match /\[WARNING\] Method unsupported by API: '(\w+)'/, output
-    end
-
-  end
-end
diff --git a/clients/console/deltacloudc b/clients/console/deltacloudc
new file mode 100755
index 0000000..adc5d11
--- /dev/null
+++ b/clients/console/deltacloudc
@@ -0,0 +1,245 @@
+#!/usr/bin/env ruby
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+require 'rubygems'
+require 'optparse'
+require 'uri'
+require 'deltacloud'
+require 'plain_formatter'
+
+include DeltaCloud::PlainFormatter
+
+options = {
+  :verbose => false
+}
+
+@optparse = OptionParser.new do |opts|
+
+opts.banner = <<BANNER
+Usage:
+deltacloudc collection operation [options]
+
+URL format:
+API_URL=http://[user]:[password]@[api_url][port][/uri]
+  OR 
+API_URL=http://[api_url][port][/uri] with -U and -P for credentials
+
+Examples:
+
+ 1. To list collections for deltacloud api on port 3333 of server deltacloud.foo
+
+        deltacloudc -l -u http://user:password@deltacloud.foo:3333/api
+
+ 2. To list the operations for the 'images' collection:
+
+        deltacloudc images -l -U username -P password -u http://deltacloud.foo:3333/api
+
+ 3. To list all images (i.e. call the 'index' operation of 'images'):
+
+        deltacloudc images index -u http://user:password@deltacloud.foo:3333/api
+
+ 4. To get the details of image '5':
+
+        deltacloudc images show -i 5 -U username -P password -u http://deltacloud.foo:3333/api
+
+Options:
+BANNER
+  opts.on( '-i', '--id ID', 'ID for operation') { |id| options[:id] = id }
+  opts.on( '-d', '--image-id ID', 'Image ID') { |id| options[:image_id] = id }
+  opts.on( '-b', '--bucket-id ID', 'Bucket ID') {|id| options[:bucket_id] = id }
+  opts.on( '-r', '--bucket-location NAME', 'Bucket location') {|name| options[:bucket_location]
= name }
+  opts.on( '-a', '--arch ARCH', 'Architecture (x86, x86_64)') { |id| options[:architecture]
= id }
+  opts.on( '-p', '--hardware-profile HARDWARE_PROFILE', 'Hardware Profile') { |id| options[:hwp_id]
= id }
+  opts.on( '-n', '--name NAME', 'Name (for instance eg.)') { |name| options[:name] = name
}
+  opts.on( '-s', '--state STATE', 'Instance state (RUNNING, STOPPED)') { |state| options[:state]
= state }
+  opts.on( '-u', '--url URL', 'API url ($API_URL variable)') { |url| options[:api_url] =
url }
+  opts.on( '-U', '--user USER', 'API username ($API_USERNAME variable)') { |u| options[:api_user]
= u }
+  opts.on( '-P', '--password PASSWORD', 'API password ($API_PASSWORD variable)') { |p| options[:api_password]
= p }
+  opts.on( '-l', '--list', 'List collections/operations') { |id| options[:list] = true }
+  opts.on( '-h', '--help', 'Display this screen' ) { puts @optparse; Kernel.exit! }
+  opts.on( '-v', '--version', 'Display API version' ) { options[:version]=true }
+  opts.on( '-V', '--verbose', 'Print verbose messages' ) { options[:verbose]=true }
+  opts.on( '-f', '--file-path PATH', 'local path for new blob data') {|path| options[:file_path]=path
}
+  opts.on( '-m', '--blob-metadata k1=v1, k2=v2', 'Comma seperated k=v pairs for blob metadata
(for create operation)') do |meta|
+                    blob_meta = {}
+                    meta.gsub!(/ /,"")
+                    meta.scan(/(\w+)=(\w+)/).map {|k,v| blob_meta[k] = v }
+                    options[:blob_metadata] = blob_meta
+                end
+end
+
+def invalid_usage(error_msg='')
+  puts "\n ERROR: #{error_msg} \n\n"
+  puts @optparse
+  exit(1)
+end
+
+begin
+    @optparse.parse!
+rescue Exception => e
+    invalid_usage(e.message)
+end
+
+# First try to get API_URL from environment
+options[:api_url] = ENV['API_URL'] if options[:api_url].nil?
+
+if(options[:api_url].nil?)
+    invalid_usage("You must supply the url to the deltacloud api; either use '-u' flag or
set the 'API_URL' environment variable")
+end
+
+url = URI.parse(options[:api_url])
+api_url = "http://#{url.host}#{url.port ? ":#{url.port}" : ''}#{url.path}"
+
+options[:collection] = ARGV[0]
+options[:operation] = ARGV[1]
+
+# Connect to Deltacloud API and fetch all entry points
+client = DeltaCloud.new(options[:api_user] || url.user || ENV['API_USER'], options[:api_password]
|| url.password || ENV['API_PASSWORD'], api_url)
+collections = client.entry_points.keys
+
+# Exclude collection which don't have methods in client library yet
+collections.delete(:instance_states)
+#add blob collection if buckets is present
+collections << :blob if collections.include?(:buckets)
+
+# If list parameter passed print out available collection
+# with API documentation
+if options[:list] and options[:collection].nil?
+  collections.each do |c|
+    puts sprintf("%-22s", c.to_s[0, 22])
+  end
+  exit(0)
+end
+
+# If collection parameter is present and user requested list
+# print all operation defined for collection with API documentation
+if options[:list] and options[:collection]
+  #deal with blobs again - bypass 'normal' docs procedure
+  if options[:collection] =~ /blob/i
+    puts "create \t\t: Create a new blob in a specified bucket (POST /api/buckets/:bucket)"
+    puts "destroy \t: Delete a specified blob in a specified bucket (DELETE /api/buckets/:bucket/:blob)"
+    puts "show \t\t: Get details of a specified blob in a specified bucket (GET /api/buckets/:bucket/:blob)"
+    puts "data \t\t: Get the contents of a specified blob - the blob data content itself"
+    exit(0)
+  end
+  doc = client.documentation(options[:collection])
+  doc.operations.each do |c|
+    puts sprintf("%-20s: %s", c.operation, c.description)
+  end
+  exit(0)
+end
+
+if options[:version]
+  puts "Deltacloud API(#{client.driver_name}) 0.1"
+  exit(0)
+end
+
+# List items from collection (typically /instances)
+# Do same if 'index' operation is set
+if options[:collection] and ( options[:operation].nil? or options[:operation].eql?('index')
)
+  invalid_usage("Unknown collection: #{options[:collection]}") unless collections.include?(options[:collection].to_sym)
+#cannot list blobs - can only show a specific blob
+  invalid_usage("You must specify a particular blob with -i and a particular bucket with
-b") if options[:collection] =~ (/blob/i)
+  params = {}
+  params.merge!(:architecture => options[:architecture]) if options[:architecture]
+  params.merge!(:id => options[:id]) if options[:id]
+  params.merge!(:state => options[:state]) if options[:state]
+  client.send(options[:collection].to_s, params).each do |model|
+    puts format(model)
+  end
+  exit(0)
+end
+
+if options[:collection] and options[:operation]
+
+  invalid_usage("Unknown collection: #{options[:collection]}") unless collections.include?(options[:collection].to_sym)
+
+  params = {}
+  params.merge!(:id => options[:id]) if options[:id]
+
+  # If collection is set and requested operation is 'show' just 'singularize'
+  # collection name and print item with specified id (-i parameter)
+  #Blobs are a special case so deal with first -
+  if options[:collection] =~ (/blob/i)
+    invalid_usage("Please specify the bucket for this blob using the -b option") unless options[:bucket_id]
+    invalid_usage("Missing blob ID, please specify with -i option") unless options[:id]
+    params = {}
+    params.merge!(:id => options[:id], 'bucket' => options[:bucket_id])
+    params.merge!('metadata'=>options[:blob_metadata]) unless options[:blob_metadata].nil?
+    case options[:operation]
+        when 'show' then puts format(client.send( options[:collection], params))
+        when 'data' then puts client.blob_data(params)
+        when 'create' then
+            invalid_usage("Specify the location of the new blob data (full local path) using
-f option") unless options[:file_path]
+            params.merge!('file_path'=>options[:file_path])
+            blob = client.create_blob(params)
+            puts format(blob)
+        when 'destroy' then client.destroy_blob(params)
+        else invalid_usage("Please specify a valid operation for the blob collection - try
-l to see available operations")
+    end
+    exit(0)
+  end
+
+  if options[:operation].eql?('show')
+    invalid_usage("Missing ID, must be provided with --id") unless options[:id]
+    puts format(client.send(options[:collection].gsub(/s$/, ''), options[:id]))
+    exit(0)
+  end
+
+  # If collection is set and requested operation is create new instance,
+  # --image-id, --hardware-profile and --name parameters are used
+  # Returns created instance in plain form
+  if options[:collection].eql?('instances') and options[:operation].eql?('create')
+    invalid_usage("Missing image-id") unless options[:image_id]
+    if options[:name] and ! client.feature?(:instances, :user_name)
+      invalid_usage("Driver does not support user-supplied name")
+    end
+    params.merge!(:name => options[:name]) if options[:name]
+    params.merge!(:image_id => options[:image_id]) if options[:image_id]
+    params.merge!(:hwp_id => options[:hwp_id]) if options[:hwp_id]
+    instance = client.create_instance(options[:image_id], params)
+    puts format(instance)
+    exit(0)
+  end
+
+  #Create and Destroy a bucket - require the bucket id:
+  if options[:collection].eql?('buckets')
+    if options[:operation].eql?('create')
+        invalid_usage("Please specify an id for the new bucket with -i") unless options[:id]
+        bucket = client.create_bucket('id'=>options[:id], 'bucket_location'=>options[:bucket_location])
+        puts format(bucket)
+    elsif options[:operation].eql?('destroy')
+        invalid_usage("Please specify the bucket you wish to destroy with -i") unless options[:id]
+        client.destroy_bucket('id'=>options[:id])
+    else
+        invalid_usage("Please specify a valid operation on buckets - use -l to see valid
operations")
+    end
+    exit(0)
+  end
+
+  # All other operations above collections is done there:
+  if options[:collection].eql?('instances')
+    instance = client.instance(options[:id])
+    instance.send("#{options[:operation]}!".to_s)
+    instance = client.instance(options[:id])
+    puts format(instance)
+    exit(0)
+  end
+end
+
+# If all above passed (eg. no parameters)
+puts @optparse
diff --git a/clients/console/plain_formatter.rb b/clients/console/plain_formatter.rb
new file mode 100644
index 0000000..2e2ada3
--- /dev/null
+++ b/clients/console/plain_formatter.rb
@@ -0,0 +1,145 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module DeltaCloud
+  module PlainFormatter
+    module FormatObject
+
+      class Base
+        def initialize(obj)
+          @obj = obj
+        end
+      end
+
+      class Key < Base
+        def format
+          sprintf("%-10s | %-60s",
+              @obj.id[0,10],
+              @obj.fingerprint
+          )
+        end
+      end
+
+      class Image < Base
+        def format
+          sprintf("%-10s | %-20s | %-6s | %-20s | %15s",
+              @obj.id[0,10],
+              @obj.name ? @obj.name[0, 20]: 'unknown',
+              @obj.architecture[0,6],
+              @obj.description[0,20],
+              @obj.owner_id[0,15]
+          )
+        end
+      end
+
+      class Realm < Base
+        def format
+          sprintf("%-10s | %-15s | %-5s | %10s GB",
+            @obj.id[0, 10],
+            @obj.name[0, 15],
+            @obj.state[0,5],
+            @obj.limit.to_s[0,10]
+          )
+        end
+      end
+
+      class HardwareProfile < Base
+        def format
+          architecture = @obj.architecture ? @obj.architecture.value[0,6] : 'opaque'
+          memory = @obj.memory ? @obj.memory.value.to_s[0,10] : 'opaque'
+          storage = @obj.storage ? @obj.storage.value.to_s[0,10] : 'opaque'
+          sprintf("%-15s | %-6s | %10s | %10s ", @obj.id[0, 15],
+           architecture , memory, storage)
+        end
+      end
+
+      class Instance < Base
+        def format
+          sprintf("%-15s | %-15s | %-15s | %10s | %32s | %32s",
+            @obj.id ? @obj.id.to_s[0,15] : '-',
+            @obj.name ? @obj.name.to_s[0,15] : 'unknown',
+            @obj.image.name ? @obj.image.name.to_s[0,15] : 'unknown',
+            @obj.state ? @obj.state.to_s[0,10] : 'unknown',
+            @obj.public_addresses.collect { |a| a[:address] }.join(',')[0,32],
+            @obj.private_addresses.collect { |a| a[:address] }.join(',')[0,32]
+          )
+        end
+      end
+
+      class StorageVolume < Base
+        def format
+          sprintf("%-10s | %15s GB | %-10s | %-10s | %-15s",
+            @obj.id[0,10],
+            @obj.capacity ? @obj.capacity.to_s[0,15] : 'unknown',
+            @obj.device ? @obj.device[0,10] : 'unknown',
+            @obj.respond_to?('state') ? @obj.state[0,10] : 'unknown',
+            @obj.instance ? @obj.instance.name[0,15] : 'unknown'
+          )
+        end
+      end
+
+      class StorageSnapshot < Base
+        def format
+          sprintf("%-10s | %-15s | %-6s | %15s",
+            @obj.id[0,10],
+            @obj.storage_volume.respond_to?('name') ? @obj.storage_volume.name[0, 15] : 'unknown',
+            @obj.state ? @obj.state[0,10] : 'unknown',
+            @obj.created ? @obj.created[0,19] : 'unknown'
+          )
+        end
+      end
+
+      class Bucket < Base
+        def format
+          sprintf("%-s | %-s | %-s | %-s",
+          @obj.id,
+          @obj.name,
+          @obj.size ? @obj.size : "0",
+          @obj.instance_variables.include?("@blob_list") ? @obj.blob_list : ""
+          )
+        end
+      end
+
+      class Blob < Base
+        def format
+          sprintf("%-s | %-s | %-d | %-s | %-s | %-s " ,
+          @obj.id,
+          @obj.bucket,
+          @obj.content_length,
+          @obj.content_type,
+          @obj.last_modified,
+          @obj.user_metadata
+          )
+        end
+      end
+
+      class Driver < Base
+        def format
+          sprintf("%-15s | %-15s | %-s",
+                  @obj.id,
+                  @obj.name,
+                  @obj.url)
+        end
+      end
+    end
+
+    def format(obj)
+      object_name = obj.class.name.classify.gsub(/^DeltaCloud::API::(\w+)::/, '')
+      format_class = DeltaCloud::PlainFormatter::FormatObject.const_get(object_name)
+      format_class.new(obj).format
+    end
+
+  end
+end
diff --git a/clients/console/tests/cmd.rb b/clients/console/tests/cmd.rb
new file mode 100644
index 0000000..90fb853
--- /dev/null
+++ b/clients/console/tests/cmd.rb
@@ -0,0 +1,214 @@
+# Copyright (C) 2009-2011  Red Hat, Inc.
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+require 'rubygems'
+require 'shoulda'
+require 'tests/common'
+
+include DeltaCloud::TestHelper
+
+class CommandLineTest < Test::Unit::TestCase
+  context "a command line client" do
+
+    should "respond to --help argument" do
+      assert_nothing_raised do
+        base_client('--help')
+      end
+    end
+
+    should "return API version with --version argument" do
+      assert_match /Deltacloud API\(mock\) (\d+)\.(\d+)/, client('--version')
+    end
+
+    should "return list all collections with --list argument" do
+      output = nil
+      assert_nothing_raised do
+        output = client('--list')
+      end
+      assert_not_nil output
+      assert_match /images/, output
+      assert_match /instances/, output
+      assert_match /realms/, output
+      assert_match /hardware_profiles/, output
+    end
+
+    should 'respond with proper error when accessing unknow collection' do
+      output = client('unknown_collection')
+      assert_match /ERROR: Unknown collection:/, output
+    end
+
+  end
+end
+
+class CmdRealmTest < Test::Unit::TestCase
+  context "a realms" do
+
+    should "be listed using realms argument" do
+      output = nil
+      assert_nothing_raised do
+        output = client('realms')
+      end
+      assert_match /^us/m, output
+      assert_match /^eu/m, output
+    end
+
+    should "be filtered using show --id argument" do
+      output = nil
+      assert_nothing_raised do
+        output = client('realms show --id us')
+      end
+      assert_match /^us/, output
+      assert_no_match /^eu/, output
+    end
+
+  end
+end
+
+class CmdHardwareProfilesTest < Test::Unit::TestCase
+  context "a hardware profiles" do
+
+    should "be listed using hardware_profiles argument" do
+      output = nil
+      assert_nothing_raised do
+        output = client('hardware_profiles')
+      end
+      assert_no_warning output
+      assert_match /^m1-small/m, output
+      assert_match /^m1-large/m, output
+      assert_match /^m1-xlarge/m, output
+      assert_match /^opaque/m, output
+    end
+
+    should "be filtered using show --id argument" do
+      output = nil
+      assert_nothing_raised do
+        output = client('hardware_profiles show --id m1-large')
+      end
+      assert_no_warning output
+      assert_match /^m1-large/, output
+      assert_no_match /^m1-small/, output
+    end
+  end
+end
+
+class CmdImagesTest < Test::Unit::TestCase
+
+  context "a images" do
+
+    should "be listed using images argument" do
+      output = nil
+      assert_nothing_raised do
+        output = client('images')
+      end
+      assert_no_warning output
+      assert_match /^img2/m, output
+      assert_match /^img1/m, output
+      assert_match /^img3/m, output
+    end
+
+    should "be filtered using show --id argument" do
+      output = nil
+      assert_nothing_raised do
+        output = client('images show --id img2')
+      end
+      assert_no_warning output
+      assert_match /^img2/m, output
+      assert_no_match /^img1/m, output
+    end
+
+    should "be filtered using --arch argument" do
+      output = nil
+      assert_nothing_raised do
+        output = client('images --arch x86_64')
+      end
+      assert_no_warning output
+      assert_match /x86_64/, output
+      assert_no_match /i386/, output
+    end
+
+  end
+
+end
+
+class CmdInstancesTest < Test::Unit::TestCase
+
+  context 'an instances' do
+
+    should 'be listed using instances argument' do
+      output = nil
+      assert_nothing_raised do
+        output = client('instances')
+      end
+      assert_no_warning output
+      assert_match /^inst1/, output
+    end
+
+    should 'be filtered using --id argument' do
+      output = nil
+      assert_nothing_raised do
+        output = client('instances show --id inst0')
+      end
+      assert_no_warning output
+      assert_match /^inst0/m, output
+      assert_no_match /^inst1/m, output
+    end
+
+  end
+
+  context 'an instance' do
+
+    should 'be created supplying --image-id argument and -p argument' do
+      output = nil
+      assert_nothing_raised do
+        output = client('instances create --image-id img1 -p m1-small')
+      end
+      assert_no_warning output
+      assert_match /^inst(\d+)/, output
+      @@created_instance_id = output.match(/^inst(\d+)/).to_a.first
+    end
+
+    should 'be rebooted using reboot operation' do
+      output = nil
+      assert_nothing_raised do
+        output = client("instances reboot --id #{@@created_instance_id}")
+      end
+      assert_no_warning output
+      assert_match /#{@@created_instance_id}/, output
+      assert_match /RUNNING/, output
+    end
+
+    should 'be stopped using stop operation' do
+      output = nil
+      assert_nothing_raised do
+        output = client("instances stop --id #{@@created_instance_id}")
+      end
+      assert_no_warning output
+      assert_match /#{@@created_instance_id}/, output
+      assert_match /STOPPED/, output
+    end
+
+    should 'be destroyed using destroy operation' do
+      output = nil
+      assert_nothing_raised do
+        output = client("instances destroy --id #{@@created_instance_id}")
+      end
+      assert_no_warning output
+    end
+
+  end
+end
diff --git a/clients/console/tests/common.rb b/clients/console/tests/common.rb
new file mode 100644
index 0000000..dc5b475
--- /dev/null
+++ b/clients/console/tests/common.rb
@@ -0,0 +1,42 @@
+# Copyright (C) 2009-2011  Red Hat, Inc.
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+module DeltaCloud
+  module TestHelper
+
+    include Test::Unit::Assertions
+
+    API_URL   = "http://localhost:3001/api"
+    API_USER  = "mockuser"
+    API_PASWD = "mockpassword"
+
+    def base_client(args)
+      `bin/deltacloudc #{args}`
+    end
+
+    def client(args)
+      args = "-u http://mockuser:mockpassword@localhost:3001/api " + args
+      base_client(args)
+    end
+
+    def assert_no_warning(output)
+      assert_no_match /\[WARNING\] Method unsupported by API: '(\w+)'/, output
+    end
+
+  end
+end
-- 
1.7.10.2


Mime
View raw message