From: Matt Wagner <matt.wagner(a)redhat.com>
---
lib/aeolus_image.rb | 20 ++-
lib/aeolus_image/base_command.rb | 139 -----------------
lib/aeolus_image/build_command.rb | 68 --------
lib/aeolus_image/command/base_command.rb | 139 +++++++++++++++++
lib/aeolus_image/command/build_command.rb | 68 ++++++++
lib/aeolus_image/command/config_parser.rb | 228 ++++++++++++++++++++++++++++
lib/aeolus_image/command/delete_command.rb | 146 ++++++++++++++++++
lib/aeolus_image/command/import_command.rb | 44 ++++++
lib/aeolus_image/command/list_command.rb | 221 +++++++++++++++++++++++++++
lib/aeolus_image/command/push_command.rb | 72 +++++++++
lib/aeolus_image/config_parser.rb | 228 ----------------------------
lib/aeolus_image/delete_command.rb | 146 ------------------
lib/aeolus_image/import_command.rb | 44 ------
lib/aeolus_image/list_command.rb | 221 ---------------------------
lib/aeolus_image/model/image.rb | 27 ++++
lib/aeolus_image/model/image_build.rb | 43 +++++
lib/aeolus_image/model/provider_image.rb | 32 ++++
lib/aeolus_image/model/target_image.rb | 27 ++++
lib/aeolus_image/model/warehouse_client.rb | 165 ++++++++++++++++++++
lib/aeolus_image/model/warehouse_model.rb | 135 ++++++++++++++++
lib/aeolus_image/push_command.rb | 72 ---------
21 files changed, 1360 insertions(+), 925 deletions(-)
delete mode 100644 lib/aeolus_image/base_command.rb
delete mode 100644 lib/aeolus_image/build_command.rb
create mode 100644 lib/aeolus_image/command/base_command.rb
create mode 100644 lib/aeolus_image/command/build_command.rb
create mode 100644 lib/aeolus_image/command/config_parser.rb
create mode 100644 lib/aeolus_image/command/delete_command.rb
create mode 100644 lib/aeolus_image/command/import_command.rb
create mode 100644 lib/aeolus_image/command/list_command.rb
create mode 100644 lib/aeolus_image/command/push_command.rb
delete mode 100644 lib/aeolus_image/config_parser.rb
delete mode 100644 lib/aeolus_image/delete_command.rb
delete mode 100644 lib/aeolus_image/import_command.rb
delete mode 100644 lib/aeolus_image/list_command.rb
create mode 100644 lib/aeolus_image/model/image.rb
create mode 100644 lib/aeolus_image/model/image_build.rb
create mode 100644 lib/aeolus_image/model/provider_image.rb
create mode 100644 lib/aeolus_image/model/target_image.rb
create mode 100644 lib/aeolus_image/model/warehouse_client.rb
create mode 100644 lib/aeolus_image/model/warehouse_model.rb
delete mode 100644 lib/aeolus_image/push_command.rb
diff --git a/lib/aeolus_image.rb b/lib/aeolus_image.rb
index e0f0770..7abd8f8 100644
--- a/lib/aeolus_image.rb
+++ b/lib/aeolus_image.rb
@@ -1,9 +1,15 @@
require 'optparse'
require 'logger'
-require File.join(File.dirname(__FILE__), 'aeolus_image',
'base_command')
-require File.join(File.dirname(__FILE__), 'aeolus_image',
'list_command')
-require File.join(File.dirname(__FILE__), 'aeolus_image',
'build_command')
-require File.join(File.dirname(__FILE__), 'aeolus_image',
'push_command')
-require File.join(File.dirname(__FILE__), 'aeolus_image',
'import_command')
-require File.join(File.dirname(__FILE__), 'aeolus_image',
'delete_command')
-require File.join(File.dirname(__FILE__), 'aeolus_image',
'config_parser')
\ No newline at end of file
+require File.join(File.dirname(__FILE__), 'aeolus_image/command',
'base_command')
+require File.join(File.dirname(__FILE__), 'aeolus_image/command',
'list_command')
+require File.join(File.dirname(__FILE__), 'aeolus_image/command',
'build_command')
+require File.join(File.dirname(__FILE__), 'aeolus_image/command',
'push_command')
+require File.join(File.dirname(__FILE__), 'aeolus_image/command',
'import_command')
+require File.join(File.dirname(__FILE__), 'aeolus_image/command',
'delete_command')
+require File.join(File.dirname(__FILE__), 'aeolus_image/command',
'config_parser')
+require File.join(File.dirname(__FILE__), 'aeolus_image/model',
'warehouse_client') # Not sure we need this
+require File.join(File.dirname(__FILE__), 'aeolus_image/model',
'warehouse_model') # We may be able to factor this out?
+require File.join(File.dirname(__FILE__), 'aeolus_image/model', 'image')
+require File.join(File.dirname(__FILE__), 'aeolus_image/model',
'image_build')
+require File.join(File.dirname(__FILE__), 'aeolus_image/model',
'provider_image')
+require File.join(File.dirname(__FILE__), 'aeolus_image/model',
'target_image')
\ No newline at end of file
diff --git a/lib/aeolus_image/base_command.rb b/lib/aeolus_image/base_command.rb
deleted file mode 100644
index 727153c..0000000
--- a/lib/aeolus_image/base_command.rb
+++ /dev/null
@@ -1,139 +0,0 @@
-require 'yaml'
-require 'rest_client'
-require 'nokogiri'
-
-module Aeolus
- module Image
- #This will house some methods that multiple Command classes need to use.
- class BaseCommand
- attr_accessor :options
-
- def initialize(opts={}, logger=nil)
- logger(logger)
- @options = opts
- @config_location = "~/.aeolus-cli"
- @config = load_config
- end
-
- protected
- def not_implemented
- "This option or combination is not yet implemented"
- end
-
- def logger(logger=nil)
- @logger ||= logger
- unless @logger
- @logger = Logger.new(STDOUT)
- @logger.level = Logger::INFO
- @logger.datetime_format = "%Y-%m-%d %H:%M:%S"
- end
- return @logger
- end
-
- def iwhd
- create_resource(:iwhd)
- end
-
- def conductor
- create_resource(:conductor)
- end
-
- def read_file(path)
- begin
- full_path = File.expand_path(path)
- if is_file?(path)
- File.read(full_path)
- else
- return nil
- end
- rescue
- nil
- end
- end
-
- # TODO: Consider ripping all this file-related stuff into a module or
- # class for better encapsulation and testability
- def is_file?(path)
- full_path = File.expand_path(path)
- if File.exist?(full_path) && !File.directory?(full_path)
- return true
- end
- false
- end
-
- def quit(code)
- exit(code)
- end
-
- def validate_xml_document(schema_path, xml_string)
- schema = Nokogiri::XML::RelaxNG(File.read(schema_path))
- doc = Nokogiri::XML xml_string
- schema.validate(doc)
- end
-
- def is_uuid?(id)
- uuid = Regexp.new('[\w]{8}[-][\w]{4}[-][\w]{4}[-][\w]{4}[-][\w]{12}')
- uuid.match(id).nil? ? false : true
- end
-
- private
- def load_config
- begin
- file_str = read_file(@config_location)
- if is_file?(@config_location) && !file_str.include?(":url")
- lines = File.readlines(File.expand_path((a)config_location)).map do |line|
- "#" + line
- end
- File.open(File.expand_path(@config_location), 'w') do |file|
- file.puts lines
- end
- write_file
- end
- write_file unless is_file?(@config_location)
- YAML::load(File.open(File.expand_path(@config_location)))
- rescue Errno::ENOENT
- #TODO: Create a custom exception to wrap CLI Exceptions
- raise "Unable to locate or write configuration file: \"" +
@config_location + "\""
- end
- end
-
- def write_file
- example = File.read(File.expand_path(File.dirname(__FILE__) +
"/../../examples/aeolus-cli"))
- File.open(File.expand_path(@config_location), 'a+') do |f|
- f.write(example)
- end
- end
-
- def create_resource(resource_name)
- # Check to see if config has a resource with this name
- if !(a)config.has_key?(resource_name)
- raise "Unable to determine resource: " + resource_name.to_s + "
from configuration file. Please check: " + @config_location
- return
- end
-
- #Use command line arguments for username/password
- if @options.has_key?(:username)
- if @options.has_key?(:password)
- RestClient::Resource.new(@config[resource_name][:url], :user =>
@options[:username], :password => @options[:password])
- else
- #TODO: Create a custom exception to wrap CLI Exceptions
- raise "Password not found for user: " + @options[:username]
- end
-
- #Use config for username/password
- elsif @config[resource_name].has_key?(:username)
- if @config[resource_name].has_key?(:password)
- RestClient::Resource.new(@config[resource_name][:url], :user =>
@config[resource_name][:username], :password => @config[resource_name][:password])
- else
- #TODO: Create a custom exception to wrap CLI Exceptions
- raise "Password not found for user: " +
@config[resource_name][:username]
- end
-
- # Do not use authentication
- else
- RestClient::Resource.new(@config[resource_name][:url])
- end
- end
- end
- end
-end
diff --git a/lib/aeolus_image/build_command.rb b/lib/aeolus_image/build_command.rb
deleted file mode 100644
index 07ced02..0000000
--- a/lib/aeolus_image/build_command.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require 'imagefactory'
-
-module Aeolus
- module Image
- class BuildCommand < BaseCommand
- attr_accessor :console
- def initialize(opts={}, logger=nil)
- super(opts, logger)
- default = {
- :template_str => '',
- :template => '',
- :target => [],
- :image => '',
- :build => ''
- }
- @options = default.merge(@options)
- @console = ImageFactoryConsole.new()
- @console.start
- end
-
- def run
- if combo_implemented?
- @options[:template_str] = read_file(@options[:template])
- if @options[:template_str].nil?
- puts "Cannot find specified file"
- quit(1)
- end
-
- # Validate XML against TDL Schema
- errors = validate_xml_document(File.dirname(__FILE__) +
"/../../examples/tdl.rng", @options[:template_str])
- if errors.length > 0
- puts "ERROR: The given Template does not conform to the TDL Schema, see
below for specific details:"
- errors.each do |error|
- puts "- " + error.message
- end
- quit(1)
- end
-
- #This is a temporary hack in case the agent doesn't show up on bus
immediately
- sleep(5)
- @console.build(@options[:template_str], @options[:target], @options[:image],
@options[:build]).each do |adaptor|
- puts ""
- puts "Target Image: #{adaptor.image_id}"
- puts "Image: #{adaptor.image}"
- puts "Build: #{adaptor.build}"
- puts "Status: #{adaptor.status}"
- puts "Percent Complete: #{adaptor.percent_complete}"
- end
- quit(0)
- end
- end
-
- def combo_implemented?
- if @options[:template].empty? || @options[:target].empty?
- puts "This combination of parameters is not currently supported"
- quit(1)
- end
- true
- end
-
- def quit(code)
- @console.shutdown
- super
- end
-
- end
- end
-end
diff --git a/lib/aeolus_image/command/base_command.rb
b/lib/aeolus_image/command/base_command.rb
new file mode 100644
index 0000000..727153c
--- /dev/null
+++ b/lib/aeolus_image/command/base_command.rb
@@ -0,0 +1,139 @@
+require 'yaml'
+require 'rest_client'
+require 'nokogiri'
+
+module Aeolus
+ module Image
+ #This will house some methods that multiple Command classes need to use.
+ class BaseCommand
+ attr_accessor :options
+
+ def initialize(opts={}, logger=nil)
+ logger(logger)
+ @options = opts
+ @config_location = "~/.aeolus-cli"
+ @config = load_config
+ end
+
+ protected
+ def not_implemented
+ "This option or combination is not yet implemented"
+ end
+
+ def logger(logger=nil)
+ @logger ||= logger
+ unless @logger
+ @logger = Logger.new(STDOUT)
+ @logger.level = Logger::INFO
+ @logger.datetime_format = "%Y-%m-%d %H:%M:%S"
+ end
+ return @logger
+ end
+
+ def iwhd
+ create_resource(:iwhd)
+ end
+
+ def conductor
+ create_resource(:conductor)
+ end
+
+ def read_file(path)
+ begin
+ full_path = File.expand_path(path)
+ if is_file?(path)
+ File.read(full_path)
+ else
+ return nil
+ end
+ rescue
+ nil
+ end
+ end
+
+ # TODO: Consider ripping all this file-related stuff into a module or
+ # class for better encapsulation and testability
+ def is_file?(path)
+ full_path = File.expand_path(path)
+ if File.exist?(full_path) && !File.directory?(full_path)
+ return true
+ end
+ false
+ end
+
+ def quit(code)
+ exit(code)
+ end
+
+ def validate_xml_document(schema_path, xml_string)
+ schema = Nokogiri::XML::RelaxNG(File.read(schema_path))
+ doc = Nokogiri::XML xml_string
+ schema.validate(doc)
+ end
+
+ def is_uuid?(id)
+ uuid = Regexp.new('[\w]{8}[-][\w]{4}[-][\w]{4}[-][\w]{4}[-][\w]{12}')
+ uuid.match(id).nil? ? false : true
+ end
+
+ private
+ def load_config
+ begin
+ file_str = read_file(@config_location)
+ if is_file?(@config_location) && !file_str.include?(":url")
+ lines = File.readlines(File.expand_path((a)config_location)).map do |line|
+ "#" + line
+ end
+ File.open(File.expand_path(@config_location), 'w') do |file|
+ file.puts lines
+ end
+ write_file
+ end
+ write_file unless is_file?(@config_location)
+ YAML::load(File.open(File.expand_path(@config_location)))
+ rescue Errno::ENOENT
+ #TODO: Create a custom exception to wrap CLI Exceptions
+ raise "Unable to locate or write configuration file: \"" +
@config_location + "\""
+ end
+ end
+
+ def write_file
+ example = File.read(File.expand_path(File.dirname(__FILE__) +
"/../../examples/aeolus-cli"))
+ File.open(File.expand_path(@config_location), 'a+') do |f|
+ f.write(example)
+ end
+ end
+
+ def create_resource(resource_name)
+ # Check to see if config has a resource with this name
+ if !(a)config.has_key?(resource_name)
+ raise "Unable to determine resource: " + resource_name.to_s + "
from configuration file. Please check: " + @config_location
+ return
+ end
+
+ #Use command line arguments for username/password
+ if @options.has_key?(:username)
+ if @options.has_key?(:password)
+ RestClient::Resource.new(@config[resource_name][:url], :user =>
@options[:username], :password => @options[:password])
+ else
+ #TODO: Create a custom exception to wrap CLI Exceptions
+ raise "Password not found for user: " + @options[:username]
+ end
+
+ #Use config for username/password
+ elsif @config[resource_name].has_key?(:username)
+ if @config[resource_name].has_key?(:password)
+ RestClient::Resource.new(@config[resource_name][:url], :user =>
@config[resource_name][:username], :password => @config[resource_name][:password])
+ else
+ #TODO: Create a custom exception to wrap CLI Exceptions
+ raise "Password not found for user: " +
@config[resource_name][:username]
+ end
+
+ # Do not use authentication
+ else
+ RestClient::Resource.new(@config[resource_name][:url])
+ end
+ end
+ end
+ end
+end
diff --git a/lib/aeolus_image/command/build_command.rb
b/lib/aeolus_image/command/build_command.rb
new file mode 100644
index 0000000..07ced02
--- /dev/null
+++ b/lib/aeolus_image/command/build_command.rb
@@ -0,0 +1,68 @@
+require 'imagefactory'
+
+module Aeolus
+ module Image
+ class BuildCommand < BaseCommand
+ attr_accessor :console
+ def initialize(opts={}, logger=nil)
+ super(opts, logger)
+ default = {
+ :template_str => '',
+ :template => '',
+ :target => [],
+ :image => '',
+ :build => ''
+ }
+ @options = default.merge(@options)
+ @console = ImageFactoryConsole.new()
+ @console.start
+ end
+
+ def run
+ if combo_implemented?
+ @options[:template_str] = read_file(@options[:template])
+ if @options[:template_str].nil?
+ puts "Cannot find specified file"
+ quit(1)
+ end
+
+ # Validate XML against TDL Schema
+ errors = validate_xml_document(File.dirname(__FILE__) +
"/../../examples/tdl.rng", @options[:template_str])
+ if errors.length > 0
+ puts "ERROR: The given Template does not conform to the TDL Schema, see
below for specific details:"
+ errors.each do |error|
+ puts "- " + error.message
+ end
+ quit(1)
+ end
+
+ #This is a temporary hack in case the agent doesn't show up on bus
immediately
+ sleep(5)
+ @console.build(@options[:template_str], @options[:target], @options[:image],
@options[:build]).each do |adaptor|
+ puts ""
+ puts "Target Image: #{adaptor.image_id}"
+ puts "Image: #{adaptor.image}"
+ puts "Build: #{adaptor.build}"
+ puts "Status: #{adaptor.status}"
+ puts "Percent Complete: #{adaptor.percent_complete}"
+ end
+ quit(0)
+ end
+ end
+
+ def combo_implemented?
+ if @options[:template].empty? || @options[:target].empty?
+ puts "This combination of parameters is not currently supported"
+ quit(1)
+ end
+ true
+ end
+
+ def quit(code)
+ @console.shutdown
+ super
+ end
+
+ end
+ end
+end
diff --git a/lib/aeolus_image/command/config_parser.rb
b/lib/aeolus_image/command/config_parser.rb
new file mode 100644
index 0000000..c992234
--- /dev/null
+++ b/lib/aeolus_image/command/config_parser.rb
@@ -0,0 +1,228 @@
+require 'optparse'
+require 'logger'
+
+module Aeolus
+ module Image
+ class ConfigParser
+ COMMANDS = %w(list build push import delete)
+ attr_accessor :options, :command, :args
+
+ def initialize(argv)
+ @args = argv
+ # Default options
+ @options = {}
+ parse
+ end
+
+ def process
+ # Check for command, then call appropriate Optionparser and initiate
+ # call to that class.
+ @command = @args.shift
+ # Eventually get the config file from user dir if it exists.
+ # File.expand_path("~")
+ if COMMANDS.include?(@command)
+ self.send((a)command.to_sym)
+ else
+ @args << "-h"
+ puts "Valid command required: \n\n"
+ parse
+ end
+ end
+
+ private
+ def parse
+ @optparse ||= OptionParser.new do|opts|
+ opts.banner = "Usage: aeolus-image [#{COMMANDS.join('|')}]
[general options] [command options]"
+
+ opts.separator ""
+ opts.separator "General options:"
+ opts.on('-u', '--user USERNAME', 'Conductor username')
do |user|
+ @options[:user] = user
+ end
+ opts.on('-w', '--password PASSWORD', 'Conductor
password') do |pw|
+ @options[:password] = pw
+ end
+ opts.on('-d', '--id ID', 'id for a given object') do
|id|
+ @options[:id] = id
+ end
+ opts.on('-r', '--description NAME', 'description (e.g.
"<image><name>MyImage</name></image>" or
"/home/user/myImage.xml")') do |description|
+ @options[:description] = description
+ end
+ opts.on('-r', '--provider NAME1,NAME2', Array,'name of
specific provider (ie ec2-us-east1)') do |name|
+ @options[:provider] = name
+ end
+ opts.on('-I', '--image ID', 'ID of the base image, can be
used in build and push commands, see examples') do |id|
+ @options[:image] = id
+ end
+ opts.on('-T', '--target TARGET1,TARGET2', Array, 'provider
type (ec2, rackspace, rhevm, etc)') do |name|
+ @options[:target] = name
+ end
+ opts.on('-d', '--daemon', 'run as a background
process') do
+ @options[:subcommand] = :images
+ end
+ opts.on( '-h', '--help', 'Get usage information for this
tool') do
+ puts opts
+ exit(0)
+ end
+
+ opts.separator ""
+ opts.separator "List options:"
+ opts.on('-i', '--images', 'Retrieve a list of images')
do
+ @options[:subcommand] = :images
+ end
+ opts.on('-b', '--builds ID', 'Retrieve the builds of an
image') do |id|
+ @options[:subcommand] = :builds
+ @options[:id] = id
+ end
+ opts.on('-t', '--targetimages ID', 'Retrieve the target
images from a build') do |id|
+ @options[:subcommand] = :targetimages
+ @options[:id] = id
+ end
+ opts.on('-P', '--providerimages ID', 'Retrieve the provider
images from a target image') do |id|
+ @options[:subcommand] = :providerimages
+ @options[:id] = id
+ end
+ opts.on('-g', '--targets', 'Retrieve the values available
for the --target parameter') do
+ @options[:subcommand] = :targets
+ end
+ opts.on('-p', '--providers', 'Retrieve the values available
for the --provider parameter') do
+ @options[:subcommand] = :providers
+ end
+ opts.on('-a', '--accounts', 'Retrieve the values available
for the --account parameter') do
+ @options[:subcommand] = :accounts
+ end
+
+ opts.separator ""
+ opts.separator "Build options:"
+ opts.on('-e', '--template FILE', 'path to file that
contains template xml') do |file|
+ @options[:template] = file
+ end
+
+ opts.separator ""
+ opts.separator "Push options:"
+ opts.on('-B', '--build ID', 'push all target images for a
build, to same providers as previously') do |id|
+ @options[:build] = id
+ end
+ opts.on('-A', '--account NAME', 'name of specific provider
account to use for push') do |name|
+ @options[:account] = name
+ end
+
+ opts.separator ""
+ opts.separator "Delete options:"
+ opts.on('-I', '--image ID', 'delete build image and
associated objects') do |id|
+ @options[:subcommand] = :image
+ @options[:image] = id
+ end
+ opts.on('-B', '--build ID', 'delete build and associated
objects') do |id|
+ @options[:subcommand] = :build
+ @options[:build] = id
+ end
+ opts.on('-m', '--targetimage ID', 'delete target image and
its provider images') do |id|
+ @options[:subcommand] = :target_image
+ @options[:targetimage] = id
+ end
+ opts.on('-D', '--providerimage ID', 'delete provider
image') do |id|
+ @options[:subcommand] = :provider_image
+ @options[:providerimage] = id
+ end
+ opts.on('-W', '--iwhd', 'Delete everything stored in
IWHD') do
+ @options[:subcommand] = :iwhd
+ end
+
+ opts.separator ""
+ opts.separator "List Examples:"
+ opts.separator "aeolus-image list --images # list
available images"
+ opts.separator "aeolus-image list --builds $image_id # list the
builds of an image"
+ opts.separator "aeolus-image list --targetimages $build_id # list the
target images from a build"
+ opts.separator "aeolus-image list --providerimages $target_id # list the
provider images from a target image"
+ opts.separator "aeolus-image list --providerimages all # list all
provider images"
+ opts.separator "aeolus-image list --targets # list the
values available for the --target parameter"
+ opts.separator "aeolus-image list --providers # list the
values available for the --provider parameter"
+ opts.separator "aeolus-image list --accounts # list the
values available for the --account parameter"
+
+ opts.separator ""
+ opts.separator "Build examples:"
+ opts.separator "aeolus-image build --target ec2 --template my.tmpl #
build a new image for ec2 from the template"
+ opts.separator "aeolus-image build --image $image_id # (NOT
IMPLEMENTED) rebuild the image template and targets from latest build"
+ opts.separator %q{aeolus-image build --target ec2,rackspace \ # rebuild
the image with a new template and set of targets
+ --image $image_i \
+ --template my.tmpl}
+
+ opts.separator ""
+ opts.separator "Push examples:"
+ opts.separator "aeolus-image push --provider ec2-us-east-1 --id $image_id
# initial push of an image build via image id to the specified provider"
+ opts.separator "aeolus-image push --build $build_id
# push an image build via build id to the specified provider"
+ opts.separator "aeolus-image push --account $provider_account --build
$build_id # (NOT IMPLEMENTED) ditto, using a specific provider account"
+ opts.separator "aeolus-image push --image $image_id
# (NOT IMPLEMENTED) push all the target images for the latest build"
+
+ opts.separator ""
+ opts.separator "Import examples:"
+ opts.separator "aeolus-image import --provider ec2-us-east-1 --target ec2
--id $ami_id # import an AMI from the specified provider"
+ opts.separator "aeolus-image import --provider ec2-us-east-1 --target ec2
--id $ami_id --description '<image><name>My
Image</name></image>' # import an AMI from the specified provider"
+ opts.separator "aeolus-image import --provider ec2-us-east-1 --target ec2
--id $ami_id --description <path_to_xml_file> # import an AMI from the specified
provider"
+
+ opts.separator ""
+ opts.separator "Delete examples: (DELETE CURRENTLY NOT IMPLEMENTED)
"
+ opts.separator "aeolus-image delete --build $build_id #
deletes a build, updating latest/parent references as appropriate"
+ opts.separator "aeolus-image delete --targetimage $target_image #
deletes a target image and its provider images"
+ opts.separator "aeolus-image delete --providerimage $provider_image #
deletes a provider image"
+ end
+
+ begin
+ @optparse.parse!(@args)
+ rescue OptionParser::InvalidOption
+ puts "Warning: Invalid option"
+ exit(1)
+ rescue OptionParser::MissingArgument => e
+ puts "Warning, #{e.message}"
+ exit(1)
+ end
+ end
+
+ # TODO: Remove all this boilerplate and replace with some metaprogramming,
+ # perhaps method_missing
+ def list
+ # TODO: Instantiate and call object matching command type, for example:
+ # l = ListCommand.new(@options)
+ # Each Command will call it's own internal method depending on the contents
of the hash.
+ # For the list example above, that object would call a method 'images'
based on the item
+ # @options[:subcommand] being :images, so internally that class may do something
like:
+ # self.send(@options[:subcommand])
+ if @options[:subcommand].nil?
+ # TODO: Pull out Print Usage into seporate method, and print
+ puts "Could not find subcommand for list, run `./aeolus-image --help` for
usage instructions"
+ exit(1)
+ else
+ list_command = ListCommand.new(@options)
+ list_command.send(@options[:subcommand])
+ end
+ end
+
+ def build
+ b = BuildCommand.new(@options)
+ b.run
+ end
+
+ def push
+ b = PushCommand.new(@options)
+ b.run
+ end
+
+ def import
+ import_command = ImportCommand.new(@options)
+ import_command.import_image
+ end
+
+ def delete
+ if @options[:subcommand].nil?
+ # TODO: Pull out Print Usage into seporate method, and print
+ puts "Could not find subcommand for delete, run `./aeolus-image --help`
for usage instructions"
+ exit(1)
+ else
+ delete_command = DeleteCommand.new(@options)
+ delete_command.send(@options[:subcommand])
+ end
+ end
+ end
+ end
+end
diff --git a/lib/aeolus_image/command/delete_command.rb
b/lib/aeolus_image/command/delete_command.rb
new file mode 100644
index 0000000..cd30362
--- /dev/null
+++ b/lib/aeolus_image/command/delete_command.rb
@@ -0,0 +1,146 @@
+module Aeolus
+ module Image
+ class DeleteCommand < BaseCommand
+ def initialize(opts={}, logger=nil)
+ super(opts, logger)
+ end
+
+ def provider_image
+ check_id(@options[:providerimage], "Provider Image")
+ begin
+ delete_provider_image(@options[:providerimage])
+ puts "Provider Image: '" + provider_image + "' was
succesfully deleted"
+ exit(0)
+ rescue RestClient::ResourceNotFound
+ puts "Error: Could not find Target Image with ID: '" +
provider_image + "'"
+ exit(1)
+ rescue => e
+ puts "Error: Could not delete Target Image with ID: '" +
provider_image + "'"
+ puts e.inspect
+ exit(1)
+ end
+ end
+
+ def target_image
+ check_id(@options[:targetimage], "Target Image")
+ begin
+ delete_target_image(@options[:targetimage])
+ puts "Target Image: '" + @options[:targetimage] + "' was
succesfully deleted"
+ exit(0)
+ rescue RestClient::ResourceNotFound
+ puts "Error: Could not find Target Image with ID: '" +
@options[:targetimage] + "'"
+ exit(1)
+ rescue => e
+ puts "Error: Could not delete Target Image with ID: '" +
@options[:targetimage] + "'"
+ puts e.inspect
+ exit(1)
+ end
+ end
+
+ def build
+ check_id(@options[:build], "Build")
+ begin
+ delete_build(@options[:build])
+ puts "Build: '" + @options[:build] + "' was succesfully
deleted"
+ exit(0)
+ rescue RestClient::ResourceNotFound
+ puts "Error: Could not find Build with ID: '" + @options[:build]
+ "'"
+ exit(1)
+ rescue => e
+ puts "Error: Could not delete Build with ID: '" +
@options[:build] + "'"
+ puts e.inspect
+ exit(1)
+ end
+ end
+
+ def image
+ check_id(@options[:image], "Image")
+ begin
+ delete_image(@options[:image])
+ puts "Image: '" + @options[:image] + "' was succesfully
deleted"
+ exit(0)
+ rescue RestClient::ResourceNotFound
+ puts "Error: Could not find Image with ID: '" + @options[:image]
+ "'"
+ exit(1)
+ rescue => e
+ puts "Error: Could not delete Image with ID: '" +
@options[:image] + "'"
+ puts e.inspect
+ exit(1)
+ end
+ end
+
+ # Deletes all objects. Iterates through each object to make sure any stray objects
are deleted.
+ def iwhd
+ list_command = ListCommand.new
+ list_command.list_providerimages(nil, true).each do |provider_image|
+ iwhd['/provider_images/' + provider_image].delete
+ end
+
+# list_command.list_targetimages(nil, true).each do |target_image|
+# iwhd['/target_images/' + target_image].delete
+# end
+#
+# list_command.list_builds(nil, true).each do |build|
+# iwhd['/builds/' + build].delete
+# end
+#
+# list_command.list_images.each do |image|
+# iwhd['/images/' + image].delete
+# end
+# puts "IWHD was successfully cleared"
+ exit(0)
+ end
+
+ private
+ def delete_provider_image(provider_image)
+ iwhd['/provider_images/' + provider_image].delete
+ end
+
+ def delete_target_image(target_image)
+ # Delete Provider Images
+ list_command = ListCommand.new
+ list_command.list_providerimages(target_image).each do |provider_image|
+ begin
+ delete_provider_image(provider_image)
+ rescue
+ end
+ end
+ # Delete Target Image
+ iwhd['/target_images/' + target_image].delete
+ end
+
+ def delete_build(build)
+ # Delete Target Images
+ list_command = ListCommand.new
+ list_command.list_targetimages(build).each do |target_image|
+ begin
+ delete_target_image(target_image)
+ rescue
+ end
+ end
+ # Delete Build
+ iwhd['/builds/' + build].delete
+ end
+
+ def delete_image(image)
+ # Delete Builds
+ list_command = ListCommand.new
+ list_command.list_builds(image).each do |build|
+ begin
+ delete_build(build)
+ rescue
+ end
+ end
+ # Delete Image
+ iwhd['/images/' + image].delete
+ end
+
+ def check_id(uuid, type)
+ if !(is_uuid?(uuid))
+ puts "Error: '" + uuid + "' is not a valid " + type
+ " ID"
+ exit(1)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/aeolus_image/command/import_command.rb
b/lib/aeolus_image/command/import_command.rb
new file mode 100644
index 0000000..158f740
--- /dev/null
+++ b/lib/aeolus_image/command/import_command.rb
@@ -0,0 +1,44 @@
+module Aeolus
+ module Image
+ class ImportCommand < BaseCommand
+ def initialize(opts={}, logger=nil)
+ super(opts, logger)
+ default = {
+ :image => '',
+ :build => '',
+ :id => '',
+ :description => '<image><name>' + @options[:id] +
'</name></image>',
+ :target => '',
+ :provider => ''
+ }
+ @options = default.merge(@options)
+ @console = ImageFactoryConsole.new()
+ @console.start
+ end
+
+ def import_image
+ description = read_file(@options[:description])
+ if !description.nil?
+ @options[:description] = description
+ end
+ # TODO: Validate Description XML
+
+ #This is a temporary hack in case the agent doesn't show up on bus
+ #immediately
+ sleep(5)
+ import_map = @console.import_image(@options[:image], @options[:build],
@options[:id], @options[:description], @options[:target].first,
@options[:provider].first)
+ puts ""
+ puts "Target Image: " + import_map['target_image']
+ puts "Image: " + import_map['image']
+ puts "Build: " + import_map['build']
+ puts "Provider Image: " + import_map['provider_image']
+ quit(0)
+ end
+
+ def quit(code)
+ @console.shutdown
+ super
+ end
+ end
+ end
+end
diff --git a/lib/aeolus_image/command/list_command.rb
b/lib/aeolus_image/command/list_command.rb
new file mode 100644
index 0000000..cccd382
--- /dev/null
+++ b/lib/aeolus_image/command/list_command.rb
@@ -0,0 +1,221 @@
+module Aeolus
+ module Image
+ class ListCommand < BaseCommand
+ def initialize(opts={}, logger=nil)
+ super(opts, logger)
+ end
+
+ def images
+ check_bucket_exists("images")
+ images = [["IMAGE ID", "LASTEST PUSHED BUILD",
"NAME", "TARGET", "OS", "OS VERSION",
"ARCH", "DESCRIPTION"]]
+ doc = Nokogiri::XML iwhd['/target_images'].get
+ # Check for any invalid data in iwhd
+ invalid_images = []
+ doc.xpath("/objects/object/key").each do |targetimage|
+ begin
+ build = iwhd["/target_images/" + targetimage.text +
"/build"].get
+ image = iwhd["/builds/" + build + "/image"].get
+
+ if template_info = get_template_info(image, targetimage.text)
+ images << [image] + [lastest_pushed(image)] + template_info
+ else
+ images << [image] + [lastest_pushed(image)] +[get_image_name(image),
iwhd["/target_images/" + targetimage + "/target"].get, "",
"", "", ""]
+ end
+ rescue
+ invalid_images << targetimage.text
+ end
+ end
+ format_print(images)
+
+ unless invalid_images.empty?
+ puts "\nN.B. following images were not listed, aeolus-image encountered
some invalid data in iwhd:"
+ puts invalid_images.join "\n"
+ end
+ quit(0)
+ end
+
+ def list_images
+ images = []
+ if check_bucket_exists("images").nil?
+ return images
+ end
+
+ doc = Nokogiri::XML iwhd['/images'].get
+ doc.xpath("/objects/object/key").each do |image|
+ images << image.text
+ end
+ images
+ end
+
+ def builds
+ builds = [["Build ID"]]
+ list_builds(@options[:id]).each do |b|
+ builds << [b]
+ end
+ format_print(builds)
+ quit(0)
+ end
+
+ def list_builds(image, all=false)
+ builds = []
+ if check_bucket_exists("builds").nil?
+ return builds
+ end
+
+ doc = Nokogiri::XML iwhd['/builds'].get
+ doc.xpath("/objects/object/key").each do |build|
+ if all || (iwhd['/builds/' + build.text + "/image"].get ==
image)
+ builds << build.text
+ end
+ end
+ builds
+ end
+
+ def targetimages
+ targetimages = [["Target Image Id"]]
+ list_targetimages(@options[:id]).each do |ti|
+ targetimages << [ti]
+ end
+ format_print(targetimages)
+ quit(0)
+ end
+
+ def list_targetimages(build, all=false)
+ targetimages = []
+ if check_bucket_exists("target_images").nil?
+ return targetimages
+ end
+
+ doc = Nokogiri::XML iwhd['/target_images'].get
+ doc.xpath("/objects/object/key").each do |target_image|
+ begin
+ if all || (iwhd['/target_images/' + target_image.text +
"/build"].get == build)
+ targetimages << target_image.text
+ end
+ rescue RestClient::ResourceNotFound
+ end
+ end
+ targetimages
+ end
+
+ def providerimages
+ providerimages = [["PROVIDER IMAGE", "PROVIDER", "TARGET
IMAGE", "TARGET IDENTIFIER", "IMAGE"]]
+ list_providerimages(@options[:id], (@options[:id] == "all")).each do
|pi|
+ providerimages << pi
+ end
+ format_print(providerimages)
+ quit(0)
+ end
+
+ def list_providerimages(targetimage, all=false)
+ providerimages = []
+ if check_bucket_exists("provider_images").nil?
+ return providerimages
+ end
+
+ doc = Nokogiri::XML iwhd['/provider_images'].get
+ doc.xpath("/objects/object/key").each do |provider_image|
+ begin
+ thistargetimage = iwhd["/provider_images/" + provider_image.text +
"/target_image"].get
+ if all || (thistargetimage == targetimage)
+ build = iwhd["/target_images/" + thistargetimage +
"/build"].get
+ image = iwhd["/builds/" + build + "/image"].get
+ providerimages << [provider_image.text] +
[iwhd["/provider_images/" + provider_image.text + "/provider"].get] +
[thistargetimage] + [iwhd["/provider_images/" + provider_image.text +
"/target_identifier"].get] + [image]
+ end
+ rescue RestClient::ResourceNotFound
+ end
+ end
+ providerimages
+ end
+
+ def targets
+ targets = [["NAME", "TARGET CODE"]]
+ targets << ["Mock", "mock"]
+ targets << ["Amazon EC2", "ec2"]
+ targets << ["RHEV-M", "rhevm"]
+ targets << ["VMware vSphere", "vsphere"]
+ targets << ["Condor Cloud", "condor_cloud"]
+ format_print(targets)
+ quit(0)
+ end
+
+ def providers
+ print_values = [["NAME", "TYPE", "URL"]]
+
+ doc = Nokogiri::XML conductor['/providers'].get
+ doc.xpath("/providers/provider").each do |provider|
+ print_values << [provider.xpath("name").text,
provider.xpath("provider_type").text, provider.xpath("url").text]
+ end
+
+ format_print(print_values)
+ quit(0)
+ end
+
+ def accounts
+ print_values = [["NAME", "PROVIDER", "PROVIDER
TYPE"]]
+ doc = Nokogiri::XML conductor['/provider_accounts/'].get
+ doc.xpath("/provider_accounts/provider_account").each do |account|
+ print_values << [account.xpath("name").text,
account.xpath("provider").text, account.xpath("provider_type").text]
+ end
+
+ format_print(print_values)
+ quit(0)
+ end
+
+ private
+ # Takes a 2D array of strings and neatly prints them to STDOUT
+ def format_print(print_values)
+ widths = Array.new(print_values[0].size, 0)
+ print_values.each do |print_value|
+ widths = widths.zip(print_value).map! {|width, value| value.length > width ?
value.length : width }
+ end
+
+ print_values.each do |print_value|
+ widths.zip(print_value) do |width, value|
+ printf("%-#{width + 5}s", value)
+ end
+ puts ""
+ end
+ end
+
+ def get_template_info(image, targetimage)
+ begin
+ template = Nokogiri::XML iwhd["/templates/" +
iwhd["/target_images/" + targetimage + "/template"].get].get
+ [template.xpath("/template/name").text,
+ iwhd["/target_images/" + targetimage + "/target"].get,
+ template.xpath("/template/os/name").text,
+ template.xpath("/template/os/version").text,
+ template.xpath("/template/os/arch").text,
+ template.xpath("/template/description").text]
+ rescue
+ end
+ end
+
+ def get_image_name(image)
+ begin
+ template_xml = Nokogiri::XML iwhd["images/" + image].get
+ template_xml.xpath("/image/name").text
+ rescue
+ ""
+ end
+ end
+
+ def lastest_pushed(image)
+ begin
+ build = iwhd["/images/" + image + "/latest_build"].get
+ build.nil? ? "" : build
+ rescue
+ ""
+ end
+ end
+
+ def check_bucket_exists(bucket)
+ begin
+ iwhd["/" + bucket].get
+ rescue
+ nil
+ end
+ end
+ end
+ end
+end
diff --git a/lib/aeolus_image/command/push_command.rb
b/lib/aeolus_image/command/push_command.rb
new file mode 100644
index 0000000..47baec6
--- /dev/null
+++ b/lib/aeolus_image/command/push_command.rb
@@ -0,0 +1,72 @@
+require 'rest_client'
+
+module Aeolus
+ module Image
+ class PushCommand < BaseCommand
+ attr_accessor :console
+ def initialize(opts={}, logger=nil)
+ super(opts, logger)
+ default = {
+ :provider => [],
+ :id => '',
+ :build => ''
+ }
+ @options = default.merge(@options)
+ @console = ImageFactoryConsole.new()
+ @console.start
+ end
+ def run
+ begin
+ if combo_implemented?
+ if !@options[:id].empty? && pushed?(@options[:id])
+ puts "ERROR: This image has already been pushed, to push to another
provider please push via build-id rather than image-id"
+ puts "e.g. aeolus-image push --provider <provider> --build
<build-id>"
+ quit(1)
+ end
+
+ sleep(5)
+ @console.push(@options[:provider], get_creds, @options[:id],
@options[:build]).each do |adaptor|
+ puts ""
+ puts "Provider Image: #{adaptor.image_id}"
+ puts "Image: #{adaptor.image}"
+ puts "Build: #{adaptor.build}"
+ puts "Status: #{adaptor.status}"
+ puts "Percent Complete: #{adaptor.percent_complete}"
+ end
+ quit(0)
+ end
+ rescue
+ puts "An Error occured whilst trying to push this build, please check
aeolus-image --help for details on how to use this command"
+ quit(1)
+ end
+ end
+
+ def get_creds
+ conductor['provider_accounts'].get
+ end
+
+ def combo_implemented?
+ if @options[:provider].empty? || (@options[:build].empty? &&
@options[:id].empty?)
+ puts "This combination of parameters is not currently supported"
+ quit(1)
+ end
+ true
+ end
+
+ private
+ def quit(code)
+ @console.shutdown
+ exit(code)
+ end
+
+ def pushed?(image)
+ begin
+ uuid = Regexp.new('[\w]{8}[-][\w]{4}[-][\w]{4}[-][\w]{4}[-][\w]{12}')
+ uuid.match(iwhd["/images/" + image +
"/latest_unpushed"].get).nil? ? true : false
+ rescue
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/lib/aeolus_image/config_parser.rb b/lib/aeolus_image/config_parser.rb
deleted file mode 100644
index c992234..0000000
--- a/lib/aeolus_image/config_parser.rb
+++ /dev/null
@@ -1,228 +0,0 @@
-require 'optparse'
-require 'logger'
-
-module Aeolus
- module Image
- class ConfigParser
- COMMANDS = %w(list build push import delete)
- attr_accessor :options, :command, :args
-
- def initialize(argv)
- @args = argv
- # Default options
- @options = {}
- parse
- end
-
- def process
- # Check for command, then call appropriate Optionparser and initiate
- # call to that class.
- @command = @args.shift
- # Eventually get the config file from user dir if it exists.
- # File.expand_path("~")
- if COMMANDS.include?(@command)
- self.send((a)command.to_sym)
- else
- @args << "-h"
- puts "Valid command required: \n\n"
- parse
- end
- end
-
- private
- def parse
- @optparse ||= OptionParser.new do|opts|
- opts.banner = "Usage: aeolus-image [#{COMMANDS.join('|')}]
[general options] [command options]"
-
- opts.separator ""
- opts.separator "General options:"
- opts.on('-u', '--user USERNAME', 'Conductor username')
do |user|
- @options[:user] = user
- end
- opts.on('-w', '--password PASSWORD', 'Conductor
password') do |pw|
- @options[:password] = pw
- end
- opts.on('-d', '--id ID', 'id for a given object') do
|id|
- @options[:id] = id
- end
- opts.on('-r', '--description NAME', 'description (e.g.
"<image><name>MyImage</name></image>" or
"/home/user/myImage.xml")') do |description|
- @options[:description] = description
- end
- opts.on('-r', '--provider NAME1,NAME2', Array,'name of
specific provider (ie ec2-us-east1)') do |name|
- @options[:provider] = name
- end
- opts.on('-I', '--image ID', 'ID of the base image, can be
used in build and push commands, see examples') do |id|
- @options[:image] = id
- end
- opts.on('-T', '--target TARGET1,TARGET2', Array, 'provider
type (ec2, rackspace, rhevm, etc)') do |name|
- @options[:target] = name
- end
- opts.on('-d', '--daemon', 'run as a background
process') do
- @options[:subcommand] = :images
- end
- opts.on( '-h', '--help', 'Get usage information for this
tool') do
- puts opts
- exit(0)
- end
-
- opts.separator ""
- opts.separator "List options:"
- opts.on('-i', '--images', 'Retrieve a list of images')
do
- @options[:subcommand] = :images
- end
- opts.on('-b', '--builds ID', 'Retrieve the builds of an
image') do |id|
- @options[:subcommand] = :builds
- @options[:id] = id
- end
- opts.on('-t', '--targetimages ID', 'Retrieve the target
images from a build') do |id|
- @options[:subcommand] = :targetimages
- @options[:id] = id
- end
- opts.on('-P', '--providerimages ID', 'Retrieve the provider
images from a target image') do |id|
- @options[:subcommand] = :providerimages
- @options[:id] = id
- end
- opts.on('-g', '--targets', 'Retrieve the values available
for the --target parameter') do
- @options[:subcommand] = :targets
- end
- opts.on('-p', '--providers', 'Retrieve the values available
for the --provider parameter') do
- @options[:subcommand] = :providers
- end
- opts.on('-a', '--accounts', 'Retrieve the values available
for the --account parameter') do
- @options[:subcommand] = :accounts
- end
-
- opts.separator ""
- opts.separator "Build options:"
- opts.on('-e', '--template FILE', 'path to file that
contains template xml') do |file|
- @options[:template] = file
- end
-
- opts.separator ""
- opts.separator "Push options:"
- opts.on('-B', '--build ID', 'push all target images for a
build, to same providers as previously') do |id|
- @options[:build] = id
- end
- opts.on('-A', '--account NAME', 'name of specific provider
account to use for push') do |name|
- @options[:account] = name
- end
-
- opts.separator ""
- opts.separator "Delete options:"
- opts.on('-I', '--image ID', 'delete build image and
associated objects') do |id|
- @options[:subcommand] = :image
- @options[:image] = id
- end
- opts.on('-B', '--build ID', 'delete build and associated
objects') do |id|
- @options[:subcommand] = :build
- @options[:build] = id
- end
- opts.on('-m', '--targetimage ID', 'delete target image and
its provider images') do |id|
- @options[:subcommand] = :target_image
- @options[:targetimage] = id
- end
- opts.on('-D', '--providerimage ID', 'delete provider
image') do |id|
- @options[:subcommand] = :provider_image
- @options[:providerimage] = id
- end
- opts.on('-W', '--iwhd', 'Delete everything stored in
IWHD') do
- @options[:subcommand] = :iwhd
- end
-
- opts.separator ""
- opts.separator "List Examples:"
- opts.separator "aeolus-image list --images # list
available images"
- opts.separator "aeolus-image list --builds $image_id # list the
builds of an image"
- opts.separator "aeolus-image list --targetimages $build_id # list the
target images from a build"
- opts.separator "aeolus-image list --providerimages $target_id # list the
provider images from a target image"
- opts.separator "aeolus-image list --providerimages all # list all
provider images"
- opts.separator "aeolus-image list --targets # list the
values available for the --target parameter"
- opts.separator "aeolus-image list --providers # list the
values available for the --provider parameter"
- opts.separator "aeolus-image list --accounts # list the
values available for the --account parameter"
-
- opts.separator ""
- opts.separator "Build examples:"
- opts.separator "aeolus-image build --target ec2 --template my.tmpl #
build a new image for ec2 from the template"
- opts.separator "aeolus-image build --image $image_id # (NOT
IMPLEMENTED) rebuild the image template and targets from latest build"
- opts.separator %q{aeolus-image build --target ec2,rackspace \ # rebuild
the image with a new template and set of targets
- --image $image_i \
- --template my.tmpl}
-
- opts.separator ""
- opts.separator "Push examples:"
- opts.separator "aeolus-image push --provider ec2-us-east-1 --id $image_id
# initial push of an image build via image id to the specified provider"
- opts.separator "aeolus-image push --build $build_id
# push an image build via build id to the specified provider"
- opts.separator "aeolus-image push --account $provider_account --build
$build_id # (NOT IMPLEMENTED) ditto, using a specific provider account"
- opts.separator "aeolus-image push --image $image_id
# (NOT IMPLEMENTED) push all the target images for the latest build"
-
- opts.separator ""
- opts.separator "Import examples:"
- opts.separator "aeolus-image import --provider ec2-us-east-1 --target ec2
--id $ami_id # import an AMI from the specified provider"
- opts.separator "aeolus-image import --provider ec2-us-east-1 --target ec2
--id $ami_id --description '<image><name>My
Image</name></image>' # import an AMI from the specified provider"
- opts.separator "aeolus-image import --provider ec2-us-east-1 --target ec2
--id $ami_id --description <path_to_xml_file> # import an AMI from the specified
provider"
-
- opts.separator ""
- opts.separator "Delete examples: (DELETE CURRENTLY NOT IMPLEMENTED)
"
- opts.separator "aeolus-image delete --build $build_id #
deletes a build, updating latest/parent references as appropriate"
- opts.separator "aeolus-image delete --targetimage $target_image #
deletes a target image and its provider images"
- opts.separator "aeolus-image delete --providerimage $provider_image #
deletes a provider image"
- end
-
- begin
- @optparse.parse!(@args)
- rescue OptionParser::InvalidOption
- puts "Warning: Invalid option"
- exit(1)
- rescue OptionParser::MissingArgument => e
- puts "Warning, #{e.message}"
- exit(1)
- end
- end
-
- # TODO: Remove all this boilerplate and replace with some metaprogramming,
- # perhaps method_missing
- def list
- # TODO: Instantiate and call object matching command type, for example:
- # l = ListCommand.new(@options)
- # Each Command will call it's own internal method depending on the contents
of the hash.
- # For the list example above, that object would call a method 'images'
based on the item
- # @options[:subcommand] being :images, so internally that class may do something
like:
- # self.send(@options[:subcommand])
- if @options[:subcommand].nil?
- # TODO: Pull out Print Usage into seporate method, and print
- puts "Could not find subcommand for list, run `./aeolus-image --help` for
usage instructions"
- exit(1)
- else
- list_command = ListCommand.new(@options)
- list_command.send(@options[:subcommand])
- end
- end
-
- def build
- b = BuildCommand.new(@options)
- b.run
- end
-
- def push
- b = PushCommand.new(@options)
- b.run
- end
-
- def import
- import_command = ImportCommand.new(@options)
- import_command.import_image
- end
-
- def delete
- if @options[:subcommand].nil?
- # TODO: Pull out Print Usage into seporate method, and print
- puts "Could not find subcommand for delete, run `./aeolus-image --help`
for usage instructions"
- exit(1)
- else
- delete_command = DeleteCommand.new(@options)
- delete_command.send(@options[:subcommand])
- end
- end
- end
- end
-end
diff --git a/lib/aeolus_image/delete_command.rb b/lib/aeolus_image/delete_command.rb
deleted file mode 100644
index cd30362..0000000
--- a/lib/aeolus_image/delete_command.rb
+++ /dev/null
@@ -1,146 +0,0 @@
-module Aeolus
- module Image
- class DeleteCommand < BaseCommand
- def initialize(opts={}, logger=nil)
- super(opts, logger)
- end
-
- def provider_image
- check_id(@options[:providerimage], "Provider Image")
- begin
- delete_provider_image(@options[:providerimage])
- puts "Provider Image: '" + provider_image + "' was
succesfully deleted"
- exit(0)
- rescue RestClient::ResourceNotFound
- puts "Error: Could not find Target Image with ID: '" +
provider_image + "'"
- exit(1)
- rescue => e
- puts "Error: Could not delete Target Image with ID: '" +
provider_image + "'"
- puts e.inspect
- exit(1)
- end
- end
-
- def target_image
- check_id(@options[:targetimage], "Target Image")
- begin
- delete_target_image(@options[:targetimage])
- puts "Target Image: '" + @options[:targetimage] + "' was
succesfully deleted"
- exit(0)
- rescue RestClient::ResourceNotFound
- puts "Error: Could not find Target Image with ID: '" +
@options[:targetimage] + "'"
- exit(1)
- rescue => e
- puts "Error: Could not delete Target Image with ID: '" +
@options[:targetimage] + "'"
- puts e.inspect
- exit(1)
- end
- end
-
- def build
- check_id(@options[:build], "Build")
- begin
- delete_build(@options[:build])
- puts "Build: '" + @options[:build] + "' was succesfully
deleted"
- exit(0)
- rescue RestClient::ResourceNotFound
- puts "Error: Could not find Build with ID: '" + @options[:build]
+ "'"
- exit(1)
- rescue => e
- puts "Error: Could not delete Build with ID: '" +
@options[:build] + "'"
- puts e.inspect
- exit(1)
- end
- end
-
- def image
- check_id(@options[:image], "Image")
- begin
- delete_image(@options[:image])
- puts "Image: '" + @options[:image] + "' was succesfully
deleted"
- exit(0)
- rescue RestClient::ResourceNotFound
- puts "Error: Could not find Image with ID: '" + @options[:image]
+ "'"
- exit(1)
- rescue => e
- puts "Error: Could not delete Image with ID: '" +
@options[:image] + "'"
- puts e.inspect
- exit(1)
- end
- end
-
- # Deletes all objects. Iterates through each object to make sure any stray objects
are deleted.
- def iwhd
- list_command = ListCommand.new
- list_command.list_providerimages(nil, true).each do |provider_image|
- iwhd['/provider_images/' + provider_image].delete
- end
-
-# list_command.list_targetimages(nil, true).each do |target_image|
-# iwhd['/target_images/' + target_image].delete
-# end
-#
-# list_command.list_builds(nil, true).each do |build|
-# iwhd['/builds/' + build].delete
-# end
-#
-# list_command.list_images.each do |image|
-# iwhd['/images/' + image].delete
-# end
-# puts "IWHD was successfully cleared"
- exit(0)
- end
-
- private
- def delete_provider_image(provider_image)
- iwhd['/provider_images/' + provider_image].delete
- end
-
- def delete_target_image(target_image)
- # Delete Provider Images
- list_command = ListCommand.new
- list_command.list_providerimages(target_image).each do |provider_image|
- begin
- delete_provider_image(provider_image)
- rescue
- end
- end
- # Delete Target Image
- iwhd['/target_images/' + target_image].delete
- end
-
- def delete_build(build)
- # Delete Target Images
- list_command = ListCommand.new
- list_command.list_targetimages(build).each do |target_image|
- begin
- delete_target_image(target_image)
- rescue
- end
- end
- # Delete Build
- iwhd['/builds/' + build].delete
- end
-
- def delete_image(image)
- # Delete Builds
- list_command = ListCommand.new
- list_command.list_builds(image).each do |build|
- begin
- delete_build(build)
- rescue
- end
- end
- # Delete Image
- iwhd['/images/' + image].delete
- end
-
- def check_id(uuid, type)
- if !(is_uuid?(uuid))
- puts "Error: '" + uuid + "' is not a valid " + type
+ " ID"
- exit(1)
- end
- end
- end
- end
-end
diff --git a/lib/aeolus_image/import_command.rb b/lib/aeolus_image/import_command.rb
deleted file mode 100644
index 158f740..0000000
--- a/lib/aeolus_image/import_command.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-module Aeolus
- module Image
- class ImportCommand < BaseCommand
- def initialize(opts={}, logger=nil)
- super(opts, logger)
- default = {
- :image => '',
- :build => '',
- :id => '',
- :description => '<image><name>' + @options[:id] +
'</name></image>',
- :target => '',
- :provider => ''
- }
- @options = default.merge(@options)
- @console = ImageFactoryConsole.new()
- @console.start
- end
-
- def import_image
- description = read_file(@options[:description])
- if !description.nil?
- @options[:description] = description
- end
- # TODO: Validate Description XML
-
- #This is a temporary hack in case the agent doesn't show up on bus
- #immediately
- sleep(5)
- import_map = @console.import_image(@options[:image], @options[:build],
@options[:id], @options[:description], @options[:target].first,
@options[:provider].first)
- puts ""
- puts "Target Image: " + import_map['target_image']
- puts "Image: " + import_map['image']
- puts "Build: " + import_map['build']
- puts "Provider Image: " + import_map['provider_image']
- quit(0)
- end
-
- def quit(code)
- @console.shutdown
- super
- end
- end
- end
-end
diff --git a/lib/aeolus_image/list_command.rb b/lib/aeolus_image/list_command.rb
deleted file mode 100644
index cccd382..0000000
--- a/lib/aeolus_image/list_command.rb
+++ /dev/null
@@ -1,221 +0,0 @@
-module Aeolus
- module Image
- class ListCommand < BaseCommand
- def initialize(opts={}, logger=nil)
- super(opts, logger)
- end
-
- def images
- check_bucket_exists("images")
- images = [["IMAGE ID", "LASTEST PUSHED BUILD",
"NAME", "TARGET", "OS", "OS VERSION",
"ARCH", "DESCRIPTION"]]
- doc = Nokogiri::XML iwhd['/target_images'].get
- # Check for any invalid data in iwhd
- invalid_images = []
- doc.xpath("/objects/object/key").each do |targetimage|
- begin
- build = iwhd["/target_images/" + targetimage.text +
"/build"].get
- image = iwhd["/builds/" + build + "/image"].get
-
- if template_info = get_template_info(image, targetimage.text)
- images << [image] + [lastest_pushed(image)] + template_info
- else
- images << [image] + [lastest_pushed(image)] +[get_image_name(image),
iwhd["/target_images/" + targetimage + "/target"].get, "",
"", "", ""]
- end
- rescue
- invalid_images << targetimage.text
- end
- end
- format_print(images)
-
- unless invalid_images.empty?
- puts "\nN.B. following images were not listed, aeolus-image encountered
some invalid data in iwhd:"
- puts invalid_images.join "\n"
- end
- quit(0)
- end
-
- def list_images
- images = []
- if check_bucket_exists("images").nil?
- return images
- end
-
- doc = Nokogiri::XML iwhd['/images'].get
- doc.xpath("/objects/object/key").each do |image|
- images << image.text
- end
- images
- end
-
- def builds
- builds = [["Build ID"]]
- list_builds(@options[:id]).each do |b|
- builds << [b]
- end
- format_print(builds)
- quit(0)
- end
-
- def list_builds(image, all=false)
- builds = []
- if check_bucket_exists("builds").nil?
- return builds
- end
-
- doc = Nokogiri::XML iwhd['/builds'].get
- doc.xpath("/objects/object/key").each do |build|
- if all || (iwhd['/builds/' + build.text + "/image"].get ==
image)
- builds << build.text
- end
- end
- builds
- end
-
- def targetimages
- targetimages = [["Target Image Id"]]
- list_targetimages(@options[:id]).each do |ti|
- targetimages << [ti]
- end
- format_print(targetimages)
- quit(0)
- end
-
- def list_targetimages(build, all=false)
- targetimages = []
- if check_bucket_exists("target_images").nil?
- return targetimages
- end
-
- doc = Nokogiri::XML iwhd['/target_images'].get
- doc.xpath("/objects/object/key").each do |target_image|
- begin
- if all || (iwhd['/target_images/' + target_image.text +
"/build"].get == build)
- targetimages << target_image.text
- end
- rescue RestClient::ResourceNotFound
- end
- end
- targetimages
- end
-
- def providerimages
- providerimages = [["PROVIDER IMAGE", "PROVIDER", "TARGET
IMAGE", "TARGET IDENTIFIER", "IMAGE"]]
- list_providerimages(@options[:id], (@options[:id] == "all")).each do
|pi|
- providerimages << pi
- end
- format_print(providerimages)
- quit(0)
- end
-
- def list_providerimages(targetimage, all=false)
- providerimages = []
- if check_bucket_exists("provider_images").nil?
- return providerimages
- end
-
- doc = Nokogiri::XML iwhd['/provider_images'].get
- doc.xpath("/objects/object/key").each do |provider_image|
- begin
- thistargetimage = iwhd["/provider_images/" + provider_image.text +
"/target_image"].get
- if all || (thistargetimage == targetimage)
- build = iwhd["/target_images/" + thistargetimage +
"/build"].get
- image = iwhd["/builds/" + build + "/image"].get
- providerimages << [provider_image.text] +
[iwhd["/provider_images/" + provider_image.text + "/provider"].get] +
[thistargetimage] + [iwhd["/provider_images/" + provider_image.text +
"/target_identifier"].get] + [image]
- end
- rescue RestClient::ResourceNotFound
- end
- end
- providerimages
- end
-
- def targets
- targets = [["NAME", "TARGET CODE"]]
- targets << ["Mock", "mock"]
- targets << ["Amazon EC2", "ec2"]
- targets << ["RHEV-M", "rhevm"]
- targets << ["VMware vSphere", "vsphere"]
- targets << ["Condor Cloud", "condor_cloud"]
- format_print(targets)
- quit(0)
- end
-
- def providers
- print_values = [["NAME", "TYPE", "URL"]]
-
- doc = Nokogiri::XML conductor['/providers'].get
- doc.xpath("/providers/provider").each do |provider|
- print_values << [provider.xpath("name").text,
provider.xpath("provider_type").text, provider.xpath("url").text]
- end
-
- format_print(print_values)
- quit(0)
- end
-
- def accounts
- print_values = [["NAME", "PROVIDER", "PROVIDER
TYPE"]]
- doc = Nokogiri::XML conductor['/provider_accounts/'].get
- doc.xpath("/provider_accounts/provider_account").each do |account|
- print_values << [account.xpath("name").text,
account.xpath("provider").text, account.xpath("provider_type").text]
- end
-
- format_print(print_values)
- quit(0)
- end
-
- private
- # Takes a 2D array of strings and neatly prints them to STDOUT
- def format_print(print_values)
- widths = Array.new(print_values[0].size, 0)
- print_values.each do |print_value|
- widths = widths.zip(print_value).map! {|width, value| value.length > width ?
value.length : width }
- end
-
- print_values.each do |print_value|
- widths.zip(print_value) do |width, value|
- printf("%-#{width + 5}s", value)
- end
- puts ""
- end
- end
-
- def get_template_info(image, targetimage)
- begin
- template = Nokogiri::XML iwhd["/templates/" +
iwhd["/target_images/" + targetimage + "/template"].get].get
- [template.xpath("/template/name").text,
- iwhd["/target_images/" + targetimage + "/target"].get,
- template.xpath("/template/os/name").text,
- template.xpath("/template/os/version").text,
- template.xpath("/template/os/arch").text,
- template.xpath("/template/description").text]
- rescue
- end
- end
-
- def get_image_name(image)
- begin
- template_xml = Nokogiri::XML iwhd["images/" + image].get
- template_xml.xpath("/image/name").text
- rescue
- ""
- end
- end
-
- def lastest_pushed(image)
- begin
- build = iwhd["/images/" + image + "/latest_build"].get
- build.nil? ? "" : build
- rescue
- ""
- end
- end
-
- def check_bucket_exists(bucket)
- begin
- iwhd["/" + bucket].get
- rescue
- nil
- end
- end
- end
- end
-end
diff --git a/lib/aeolus_image/model/image.rb b/lib/aeolus_image/model/image.rb
new file mode 100644
index 0000000..73c1b24
--- /dev/null
+++ b/lib/aeolus_image/model/image.rb
@@ -0,0 +1,27 @@
+module Aeolus
+ module Image
+ class Image < WarehouseModel
+ @bucket_name = 'images'
+
+ def initialize(attrs)
+ attrs.each do |k,v|
+ if k.to_sym == :latest_build
+ sym = :attr_writer
+ else
+ sym = :attr_accessor
+ end
+ self.class.send(sym, k.to_sym) unless respond_to?(:"#{k}=")
+ send(:"#{k}=", v)
+ end
+ end
+
+ def latest_build
+ ImageBuild.find(@latest_build) if @latest_build
+ end
+
+ def image_builds
+ ImageBuild.find_all_by_image_uuid(self.uuid)
+ end
+ end
+ end
+end
diff --git a/lib/aeolus_image/model/image_build.rb
b/lib/aeolus_image/model/image_build.rb
new file mode 100644
index 0000000..f9ced0b
--- /dev/null
+++ b/lib/aeolus_image/model/image_build.rb
@@ -0,0 +1,43 @@
+module Aeolus
+ module Image
+ class ImageBuild < WarehouseModel
+ @bucket_name = 'builds'
+
+ def initialize(attrs)
+ attrs.each do |k,v|
+ if k.to_sym == :image
+ sym = :attr_writer
+ else
+ sym = :attr_accessor
+ end
+ self.class.send(sym, k.to_sym) unless respond_to?(:"#{k}=")
+ send(:"#{k}=", v)
+ end
+ end
+
+ def self.find_all_by_image_uuid(uuid)
+ self.set_warehouse_and_bucket if self.bucket.nil?
+ self.bucket.objects.map do |wh_object|
+ if wh_object.attr('image')[1] == uuid
+ ImageBuild.new(wh_object.attrs(wh_object.attr_list))
+ end
+ end.compact
+ end
+
+ def image
+ Image.find(@image) if @image
+ end
+
+ def target_images
+ TargetImage.all.select {|ti| ti.build and (ti.build.uuid == self.uuid)}
+ end
+
+ def provider_images
+ targets = target_images
+ ProviderImage.all.select do |pi|
+ targets.include?(pi.target_image)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/aeolus_image/model/provider_image.rb
b/lib/aeolus_image/model/provider_image.rb
new file mode 100644
index 0000000..44f576d
--- /dev/null
+++ b/lib/aeolus_image/model/provider_image.rb
@@ -0,0 +1,32 @@
+module Aeolus
+ module Image
+ class ProviderImage < WarehouseModel
+ @bucket_name = 'provider_images'
+
+ def initialize(attrs)
+ attrs.each do |k,v|
+ if [:provider, :target_image].include?(k.to_sym)
+ sym = :attr_writer
+ else
+ sym = :attr_accessor
+ end
+ self.class.send(sym, k.to_sym) unless respond_to?(:"#{k}=")
+ send(:"#{k}=", v)
+ end
+ end
+
+ def target_image
+ TargetImage.find(@target_image) if @target_image
+ end
+
+ def provider_name
+ @provider
+ end
+
+ def provider
+ Provider.find_by_name(@provider)
+ end
+
+ end
+ end
+end
diff --git a/lib/aeolus_image/model/target_image.rb
b/lib/aeolus_image/model/target_image.rb
new file mode 100644
index 0000000..1167fd4
--- /dev/null
+++ b/lib/aeolus_image/model/target_image.rb
@@ -0,0 +1,27 @@
+module Aeolus
+ module Image
+ class TargetImage < WarehouseModel
+ @bucket_name = 'target_images'
+
+ def initialize(attrs)
+ attrs.each do |k,v|
+ if k.to_sym == :build
+ sym = :attr_writer
+ else
+ sym = :attr_accessor
+ end
+ self.class.send(sym, k.to_sym) unless respond_to?(:"#{k}=")
+ send(:"#{k}=", v)
+ end
+ end
+
+ def build
+ ImageBuild.find(@build) if @build
+ end
+
+ def provider_images
+ ProviderImage.all.select{|pi| pi.target_image and (pi.target_image.uuid ==
self.uuid)}
+ end
+ end
+ end
+end
diff --git a/lib/aeolus_image/model/warehouse_client.rb
b/lib/aeolus_image/model/warehouse_client.rb
new file mode 100644
index 0000000..fcad944
--- /dev/null
+++ b/lib/aeolus_image/model/warehouse_client.rb
@@ -0,0 +1,165 @@
+require 'rubygems'
+
+require 'rest-client'
+require 'nokogiri'
+
+#TODO: perform iwhd version-dependent URI mapping
+module Aeolus
+ module Image
+ module Warehouse
+
+ class BucketObject
+ attr_reader :key
+
+ def initialize(connection, key, bucket)
+ @connection = connection
+ @key = key
+ @bucket = bucket
+ @path = "/#{@bucket.name}/#{(a)key}"
+ end
+
+ def self.create(connection, key, bucket, body, attrs = {})
+ obj = new(connection, key, bucket)
+ obj.set_body(body)
+ obj.set_attrs(attrs)
+ obj
+ end
+
+ def body
+ @connection.do_request @path, :plain => true
+ end
+
+ def set_body(body)
+ @connection.do_request @path, :content => body, :method => :put
+ end
+
+ def attr_list
+ result = @connection.do_request @path, :content => 'op=parts',
:method => :post
+ return result.xpath('/object/object_attr/(a)name').to_a.map {|item|
item.value}
+ end
+
+ def attrs(list)
+ attrs = {}
+ list.each do |att|
+ next if att.match('-')
+ attrs[att] = (@connection.do_request("#{@path}/#{att}", :plain
=> true) rescue nil)
+ end
+ attrs
+ end
+
+ def attr(name)
+ attrs([name]).first
+ end
+
+ def set_attrs(hash)
+ hash.each do |name, content|
+ set_attr(name, content)
+ end
+ end
+
+ def set_attr(name, content)
+ path = "#{@path}/#{name}"
+ @connection.do_request path, :content => content, :method => :put
+ end
+
+ def delete!
+ @connection.do_request @path, :method => :delete
+ true
+ end
+
+ end
+
+ class Bucket
+ attr_accessor :name
+
+ def initialize(name, connection)
+ @name = name
+ @connection = connection
+ end
+
+ def to_s
+ "Bucket: #{@name}"
+ end
+
+ def object_names
+ result = @connection.do_request "/#{@name}"
+ result.xpath('/objects/object').map do |obj|
+ obj.at_xpath('./key/text()').to_s
+ end
+ end
+
+ def objects
+ object_names.map do |name|
+ object(name)
+ end
+ end
+
+ def object(key)
+ BucketObject.new @connection, key, self
+ end
+
+ def create_object(key, body, attrs)
+ BucketObject.create(@connection, key, self, body, attrs)
+ end
+
+ def include?(key)
+ object_names.include?(key)
+ end
+ end
+
+ class Connection
+ attr_accessor :uri
+
+ def initialize(uri)
+ @uri = uri
+ end
+
+ def do_request(path = '', opts={})
+ opts[:method] ||= :get
+ opts[:content] ||= ''
+ opts[:plain] ||= false
+ opts[:headers] ||= {}
+
+ result = RestClient::Request.execute :method => opts[:method], :url =>
@uri + path, :payload => opts[:content], :headers => opts[:headers]
+
+ return Nokogiri::XML result unless opts[:plain]
+ return result
+ end
+
+ end
+
+ class Client
+
+ def initialize(uri)
+ @connection = Connection.new(uri)
+ end
+
+ def create_bucket(bucket)
+ @connection.do_request "/#{bucket}", :method => :put rescue
RestClient::InternalServerError
+ Bucket.new(bucket, @connection)
+ end
+
+ def bucket(bucket)
+ Bucket.new bucket, @connection
+ end
+
+ def buckets
+ @connection.do_request.xpath('/api/link[(a)rel="bucket"]').map
do |obj|
+ obj.at_xpath('./(a)href').to_s.gsub(/.*\//, '')
+ end
+ end
+
+ def get_iwhd_version
+ result =
@connection.do_request.at_xpath('/api[@service="image_warehouse"]/@version')
+ raise "Response does not contain <api> tag or version
information" if result == nil
+ return result.value
+ end
+
+ def query(bucket_name, query_string)
+ @connection.do_request "/#{bucket_name}/_query", {:method =>
:post, :content => query_string}
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/aeolus_image/model/warehouse_model.rb
b/lib/aeolus_image/model/warehouse_model.rb
new file mode 100644
index 0000000..bc502d6
--- /dev/null
+++ b/lib/aeolus_image/model/warehouse_model.rb
@@ -0,0 +1,135 @@
+module Aeolus
+ module Image
+ # require 'warehouse_client'
+ include Warehouse
+ class BucketObjectNotFound < Exception;end
+ class BucketNotFound < Exception;end
+
+ class WarehouseModel
+
+ def ==(other_obj)
+ # If the objects have different instance variables defined, they're
definitely not ==
+ return false unless instance_variables.sort == other_obj.instance_variables.sort
+ # Otherwise, ensure that they're all the same
+ instance_variables.each do |iv|
+ return false unless other_obj.instance_variable_get(iv) ==
instance_variable_get(iv)
+ end
+ # They have the same instance variables and values, so they're equal
+ true
+ end
+
+ class << self
+ attr_accessor :warehouse, :bucket, :bucket_name
+
+ def set_warehouse_and_bucket
+ begin
+ @@config ||= load_config
+ self.warehouse = Warehouse::Client.new(@@config[:iwhd][:url])
+ self.bucket = self.warehouse.bucket(@bucket_name)
+ rescue
+ raise BucketNotFound
+ end
+ end
+
+ def bucket_objects
+ self.set_warehouse_and_bucket if self.bucket.nil?
+
+ begin
+ self.bucket.objects
+ rescue RestClient::ResourceNotFound
+ []
+ end
+ end
+
+ def first
+ obj = bucket_objects.first
+ obj ? self.new(obj.attrs(obj.attr_list)) : nil
+ end
+
+ def last
+ obj = bucket_objects.last
+ obj ? self.new(obj.attrs(obj.attr_list)) : nil
+ end
+
+ def all
+ bucket_objects.map do |wh_object|
+ self.new(wh_object.attrs(wh_object.attr_list))
+ end
+ end
+
+ def find(uuid)
+ self.set_warehouse_and_bucket if self.bucket.nil?
+ begin
+ if self.bucket.include?(uuid)
+
self.new(self.bucket.object(uuid).attrs(self.bucket.object(uuid).attr_list))
+ else
+ nil
+ end
+ rescue RestClient::ResourceNotFound
+ nil
+ end
+ end
+
+ def where(query_string)
+ self.set_warehouse_and_bucket if self.bucket.nil?
+ self.warehouse.query(@bucket_name, query_string)
+ end
+
+ protected
+ # Copy over entirely too much code to load the config file
+ def load_config
+ # TODO - Is this always the case? We should probably have /etc/aeolus-cli or
something too?
+ # Or allow Rails to override this
+ @config_location ||= "~/.aeolus-cli"
+ begin
+ file_str = read_file(@config_location)
+ if is_file?(@config_location) &&
!file_str.include?(":url")
+ lines = File.readlines(File.expand_path((a)config_location)).map do |line|
+ "#" + line
+ end
+ File.open(File.expand_path(@config_location), 'w') do |file|
+ file.puts lines
+ end
+ write_file
+ end
+ write_file unless is_file?(@config_location)
+ YAML::load(File.open(File.expand_path(@config_location)))
+ rescue Errno::ENOENT
+ #TODO: Create a custom exception to wrap CLI Exceptions
+ raise "Unable to locate or write configuration file: \"" +
@config_location + "\""
+ end
+ end
+
+ def write_file
+ example = File.read(File.expand_path(File.dirname(__FILE__) +
"/../../examples/aeolus-cli"))
+ File.open(File.expand_path(@config_location), 'a+') do |f|
+ f.write(example)
+ end
+ end
+
+ def read_file(path)
+ begin
+ full_path = File.expand_path(path)
+ if is_file?(path)
+ File.read(full_path)
+ else
+ return nil
+ end
+ rescue
+ nil
+ end
+ end
+
+ def is_file?(path)
+ full_path = File.expand_path(path)
+ if File.exist?(full_path) && !File.directory?(full_path)
+ return true
+ end
+ false
+ end
+
+ end
+
+ end
+ end
+end
diff --git a/lib/aeolus_image/push_command.rb b/lib/aeolus_image/push_command.rb
deleted file mode 100644
index 47baec6..0000000
--- a/lib/aeolus_image/push_command.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-require 'rest_client'
-
-module Aeolus
- module Image
- class PushCommand < BaseCommand
- attr_accessor :console
- def initialize(opts={}, logger=nil)
- super(opts, logger)
- default = {
- :provider => [],
- :id => '',
- :build => ''
- }
- @options = default.merge(@options)
- @console = ImageFactoryConsole.new()
- @console.start
- end
- def run
- begin
- if combo_implemented?
- if !@options[:id].empty? && pushed?(@options[:id])
- puts "ERROR: This image has already been pushed, to push to another
provider please push via build-id rather than image-id"
- puts "e.g. aeolus-image push --provider <provider> --build
<build-id>"
- quit(1)
- end
-
- sleep(5)
- @console.push(@options[:provider], get_creds, @options[:id],
@options[:build]).each do |adaptor|
- puts ""
- puts "Provider Image: #{adaptor.image_id}"
- puts "Image: #{adaptor.image}"
- puts "Build: #{adaptor.build}"
- puts "Status: #{adaptor.status}"
- puts "Percent Complete: #{adaptor.percent_complete}"
- end
- quit(0)
- end
- rescue
- puts "An Error occured whilst trying to push this build, please check
aeolus-image --help for details on how to use this command"
- quit(1)
- end
- end
-
- def get_creds
- conductor['provider_accounts'].get
- end
-
- def combo_implemented?
- if @options[:provider].empty? || (@options[:build].empty? &&
@options[:id].empty?)
- puts "This combination of parameters is not currently supported"
- quit(1)
- end
- true
- end
-
- private
- def quit(code)
- @console.shutdown
- exit(code)
- end
-
- def pushed?(image)
- begin
- uuid = Regexp.new('[\w]{8}[-][\w]{4}[-][\w]{4}[-][\w]{4}[-][\w]{12}')
- uuid.match(iwhd["/images/" + image +
"/latest_unpushed"].get).nil? ? true : false
- rescue
- true
- end
- end
- end
- end
-end
--
1.7.6