diff --git a/README.md b/README.md index 13fe2dd..2576fda 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,27 @@ Revamp of cli tooling for aeolus conductor. Thor scaffolding is in place, along with ActiveResource-backed interaction with Conductor's REST api to list or add providers. -Authentication options for the Conductor api can specified in -~/.aeolus-cli as per the old aeolus client. Or, /etc/aeolus-cli is -checked if ~/.aeolus-cli does not exist. Finally, these options may -instead be supplied on the command line with --conductor-url, ---username, and --password. +## Configuration + +Connection/auth options for the Conductor API may be specified in a +configuration file in one of three places: the file defined by the +environment variable AEOLUS_CLI_CONF, otherwise ~/.aeolus-cli (if it +exists), otherwise /etc/aeolus-cli (if it exists). Additionaly, +connection/auth options may be set or overridden from the command line +with --conductor-url, --username and --password. + +Logging levels also are set in the configuration file. + + # Sample configuration file + :conductor: + :url: http://example.com:3013/api + :username: master + :password: ofuniverse + :logging: + # one of DEBUG, WARN, INFO, ERROR or FATAL + :level: WARN + # one of STDOUT, STDERR or /path/to/logfile + :logfile: STDERR ## Exploring the command and sub command usage @@ -72,8 +88,6 @@ instead be supplied on the command line with --conductor-url, ## List providers $ aeolus provider list - I, [2012-10-31T14:18:49.411815 #10688] INFO -- : GET http://localhost:3002/api/providers.xml - I, [2012-10-31T14:18:49.411966 #10688] INFO -- : --> 200 OK 5591 (530.6ms) Name Provider Type Deltacloud Provider Deltacloud url ec2-us-east-1 ec2 us-east-1 http://qeblade30.rhq.lab.eng.bos.redhat.com:3002/api mock mock http://qeblade30.rhq.lab.eng.bos.redhat.com:3002/api @@ -83,29 +97,17 @@ instead be supplied on the command line with --conductor-url, ## Add a provider $ aeolus provider add mock-test21 --deltacloud-url http://qeblade30.rhq.lab.eng.bos.redhat.com:3002/api --provider-type mock - I, [2012-10-31T14:20:18.522110 #10826] INFO -- : GET http://localhost:3002/api/provider_types.xml - I, [2012-10-31T14:20:18.522251 #10826] INFO -- : --> 200 OK 1060 (432.9ms) - I, [2012-10-31T14:20:19.314974 #10826] INFO -- : POST http://localhost:3002/api/providers.xml - I, [2012-10-31T14:20:19.315100 #10826] INFO -- : --> 201 Created 254 (707.5ms) Provider mock-test21 added with id 23 ## Display remote error mesage when trying to add an existing provider $ aeolus provider add mock-test21 --deltacloud-url http://qeblade30.rhq.lab.eng.bos.redhat.com:3002/api --provider-type mock - I, [2012-10-31T14:20:24.297438 #10873] INFO -- : GET http://localhost:3002/api/provider_types.xml - I, [2012-10-31T14:20:24.297604 #10873] INFO -- : --> 200 OK 1060 (594.1ms) - I, [2012-10-31T14:20:24.919177 #10873] INFO -- : POST http://localhost:3002/api/providers.xml - I, [2012-10-31T14:20:24.919330 #10873] INFO -- : --> 422 100 (535.8ms) ERROR: Conductor was unable to save the provider ["Provider name has already been taken"] ## List provider accounts $ aeolus provider_account list - I, [2012-12-11T10:26:20.775263 #1864] INFO -- : GET https://localhost:443/conductor/api/provider_accounts.xml - I, [2012-12-11T10:26:20.775443 #1864] INFO -- : --> 200 OK 285 (104.1ms) - I, [2012-12-11T10:26:20.932803 #1864] INFO -- : GET https://localhost:443/conductor/api/provider_accounts/2.xml - I, [2012-12-11T10:26:20.932911 #1864] INFO -- : --> 200 OK 418 (106.7ms) Name Provider Username Quota mock mock mockuser unlimited @@ -117,18 +119,10 @@ instead be supplied on the command line with --conductor-url, mockpassword $ aeolus provider_account add mock --provider-name mock --credentials-file /tmp/credentials.xml - I, [2012-12-11T09:42:24.823114 #31824] INFO -- : GET https://localhost:443/conductor/api/providers.xml - I, [2012-12-11T09:42:24.823226 #31824] INFO -- : --> 200 OK 245 (110.0ms) - I, [2012-12-11T09:42:26.032696 #31824] INFO -- : POST https://localhost:443/conductor/api/provider_accounts.xml - I, [2012-12-11T09:42:26.032939 #31824] INFO -- : --> 201 Created 418 (1197.6ms) Provider account mock added with id 2 ## Display remote error message when trying to add an existing provider account $ aeolus provider_account add mock --provider-name mock --credentials-file /tmp/credentials.xml - I, [2012-12-11T10:31:56.555708 #2238] INFO -- : GET https://localhost:443/conductor/api/providers.xml - I, [2012-12-11T10:31:56.555953 #2238] INFO -- : --> 200 OK 245 (113.2ms) - I, [2012-12-11T10:31:56.930892 #2238] INFO -- : POST https://localhost:443/conductor/api/provider_accounts.xml - I, [2012-12-11T10:31:56.931059 #2238] INFO -- : --> 422 Unprocessable Entity 152 (357.4ms) ERROR: Conductor was unable to save the provider account ["Label has already been taken", "Username has already been taken"] diff --git a/lib/aeolus_cli/common_cli.rb b/lib/aeolus_cli/common_cli.rb index 446a47d..f4f6e89 100644 --- a/lib/aeolus_cli/common_cli.rb +++ b/lib/aeolus_cli/common_cli.rb @@ -10,7 +10,7 @@ class AeolusCli::CommonCli < Thor def initialize(*args) super - configure_conductor_connection(options) + load_aeolus_config(options) end # abstract-y methods @@ -41,17 +41,66 @@ def banner(task, namespace = nil, subcommand = false) end end - def configure_conductor_connection(options) - @config = nil - # check default config file locations - ["~/.aeolus-cli","/etc/aeolus-cli"].each do |fname| - if is_file?(fname) - @config = YAML::load(File.open(File.expand_path(fname))) - break + def load_aeolus_config(options) + # set logging defaults + ActiveResource::Base.logger = Logger.new(STDOUT) + ActiveResource::Base.logger.level = Logger::WARN + + # locate the config file if one exists + config_fname = nil + if ENV.has_key?("AEOLUS_CLI_CONF") + config_fname = ENV["AEOLUS_CLI_CONF"] + if !is_file?(config_fname) + raise AeolusCli::ConfigError.new( + "environment variable AEOLUS_CLI_CONF with value "+ + "'#{ ENV['AEOLUS_CLI_CONF']}' does not point to an existing file") + end + else + ["~/.aeolus-cli","/etc/aeolus-cli"].each do |fname| + if is_file?(fname) + config_fname = fname + break + end end end - if @config != nil - configure_active_resource + + # load the config file if we have one + if config_fname != nil + @config = YAML::load(File.open(File.expand_path(config_fname))) + if @config.has_key?(:conductor) + [:url, :password, :username].each do |key| + raise AeolusCli::ConfigError.new \ + ("Error in configuration file: #{key} is missing" + ) unless @config[:conductor].has_key?(key) + end + AeolusCli::Model::Base.site = @config[:conductor][:url] + AeolusCli::Model::Base.user = @config[:conductor][:username] + AeolusCli::Model::Base.password = @config[:conductor][:password] + else + raise AeolusCli::ConfigError.new("Error in configuration file") + end + if @config.has_key?(:logging) + if @config[:logging].has_key?(:logfile) + if @config[:logging][:logfile].upcase == "STDOUT" + ActiveResource::Base.logger = Logger.new(STDOUT) + elsif @config[:logging][:logfile].upcase == "STDERR" + ActiveResource::Base.logger = Logger.new(STDERR) + else + ActiveResource::Base.logger = + Logger.new(@config[:logging][:logfile]) + end + end + if @config[:logging].has_key?(:level) + log_level = @config[:logging][:level] + if ! ['DEBUG','WARN','INFO','ERROR','FATAL'].include?(log_level) + raise AeolusCli::ConfigError.new \ + ("log level specified in configuration #{log_level}, is not valid."+ + ". shoud be one of DEBUG, WARN, INFO, ERROR or FATAL") + else + ActiveResource::Base.logger.level = eval("Logger::#{log_level}") + end + end + end end # allow overrides from command line if options[:conductor_url] @@ -105,24 +154,6 @@ def provider_type_hash deltacloud_driver_to_provider_type end - # The two methods below which are related to loading - # site/username/password from a config file such as ~/.aeolus-cli - # are borrowed from original aeolus-cli project - def configure_active_resource - if @config.has_key?(:conductor) - [:url, :password, :username].each do |key| - raise AeolusCli::ConfigError.new( - "Error in configuration file: #{key} is missing") \ - unless @config[:conductor].has_key?(key) - end - AeolusCli::Model::Base.site = @config[:conductor][:url] - AeolusCli::Model::Base.user = @config[:conductor][:username] - AeolusCli::Model::Base.password = @config[:conductor][:password] - else - raise AeolusCli::ConfigError.new("Error in configuration file") - end - end - # TODO: Consider ripping all this file-related stuff into a module or # class for better encapsulation and testability def is_file?(path) diff --git a/spec/config_spec.rb b/spec/config_spec.rb new file mode 100644 index 0000000..9f93712 --- /dev/null +++ b/spec/config_spec.rb @@ -0,0 +1,50 @@ +require 'aeolus_cli/main' + +describe "loading configuration-file by environment variable" do + + before do + config_file = File.expand_path("spec/sample/aeolus-cli-config") + ENV['AEOLUS_CLI_CONF'] = config_file + end + + describe 'with no command line overrides' do + before do + AeolusCli::Provider.start + end + it 'the configuration file should be loaded' do + AeolusCli::Model::Base.site.to_s.should == 'http://example.com:3013/api' + AeolusCli::Model::Base.user.to_s.should == 'master' + AeolusCli::Model::Base.password.to_s.should == 'ofuniverse' + ActiveResource::Base.logger.level.should == Logger::DEBUG + end + end + + describe 'with --username override' do + before do + AeolusCli::Provider.start(["--username", "override-user"]) + end + it 'the configuration file should be loaded' do + AeolusCli::Model::Base.user.to_s.should == 'override-user' + end + end + + describe 'with --password override' do + before do + AeolusCli::Provider.start(["--password", "override-password"]) + end + it 'the configuration file should be loaded' do + AeolusCli::Model::Base.password.to_s.should == 'override-password' + end + end + + describe 'with --conductor-url override' do + before do + AeolusCli::Provider.start(["--conductor-url", + "https://localhost/conductor/api"]) + end + it 'the configuration file should be loaded' do + AeolusCli::Model::Base.site.to_s.should == + 'https://localhost/conductor/api' + end + end +end diff --git a/spec/provider_spec.rb b/spec/provider_spec.rb deleted file mode 100644 index d5a5d23..0000000 --- a/spec/provider_spec.rb +++ /dev/null @@ -1,6 +0,0 @@ -require 'aeolus_cli' -require 'aeolus_cli/provider' -# -# See cucumber tests for testing command line functionality -# Non-command line tests wil go here -# diff --git a/spec/sample/aeolus-cli-config b/spec/sample/aeolus-cli-config new file mode 100644 index 0000000..68b5940 --- /dev/null +++ b/spec/sample/aeolus-cli-config @@ -0,0 +1,8 @@ +# Sample aeolus-cli config file +:conductor: + :url: http://example.com:3013/api + :username: master + :password: ofuniverse +:logging: + :level: DEBUG + :log-file: STDERR