bin/occi
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Licensed 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 'pp'
require 'openssl'
require 'highline/import'
require 'occi-cli'
NONPASS_AUTHS = %w(none token oauth2).freeze
# get arguments and validate/parse them to an ostruct
options = Occi::Cli::OcciOpts.parse ARGV
# initialize logger
logger = Occi::Cli::Log.new(options.log[:out])
logger.level = options.log[:level]
options.log[:logger] = logger.api_log
# initialize output factory
output = Occi::Cli::ResourceOutputFactory.new options.output_format
Occi::Cli::Log.info "Starting OCCI client ..."
Occi::Cli::Log.debug "Options: #{options.inspect}"
# running with an empty password, we should ask the user for one
# if auth method is not "none"
if options.auth[:password].nil? || options.auth[:user_cert_password].nil?
Occi::Cli::Log.debug "Password is not set, asking for it now ..."
options.auth[:user_cert_password] = ask("Enter a password: ") {
|q| q.echo = '*'
} unless NONPASS_AUTHS.include?(options.auth[:type]) || (options.auth[:voms] && options.auth[:type] == "x509")
options.auth[:password] = options.auth[:user_cert_password]
end
# establish a connection
begin
Occi::Cli::Log.info "Establishing a connection to #{options.endpoint.inspect} ..."
options.auto_connect = true
connect :http, options
rescue OpenSSL::SSL::SSLError => ssl_ex
# generic SSL error raised whilst establishing a connection
# possibly an untrusted server cert or invalid user credentials
Occi::Cli::Log.fatal "An SSL error occurred! Please, make sure your credentials " \
"are valid and recognized by the endpoint! Message: #{ssl_ex.message}"
raise ssl_ex if options.debug
exit!
rescue OpenSSL::PKey::RSAError => key_ex
# generic X509 error raised whilst reading user's credentials from a file
# possibly a wrong password or mangled/unsupported credential format
Occi::Cli::Log.fatal "An X509 error occurred! Please, make sure you are using the " \
"right password and the file contains both your certificate " \
"and your private key! Message: #{key_ex.message}"
raise key_ex if options.debug
exit!
rescue Errno::ECONNREFUSED
# the remote server has refused our connection attempt(s)
# there is nothing we can do ...
Occi::Cli::Log.fatal "Connection refused by #{options.endpoint.inspect}!"
exit!
rescue Errno::ETIMEDOUT, Net::OpenTimeout, Net::ReadTimeout
# connection attempt timed out
Occi::Cli::Log.fatal "Connection to #{options.endpoint.inspect} timed out!"
exit!
rescue => ex
# something went wrong during the execution
# hide the stack trace in non-debug modes
Occi::Cli::Log.fatal "An error occurred! Message: #{ex.message}"
raise ex if options.debug
exit!
end
# dump the occi model provided by the server and exit
if options.dump_model
if !model.respond_to? :instance_variables
Occi::Cli::Log.fatal "Your Ruby doesn't support 'instance_variables' calls!"
exit!
end
collection = model.get options.filter
# iterate through available instance variables
collection.instance_variables.each do |inst_var_sym|
puts "#"*79
puts "Dumping #{inst_var_sym.to_s.inspect}:"
inst_var = collection.instance_variable_get(inst_var_sym)
next unless inst_var.respond_to? :each
# iterate through collection elements
inst_var.each do |coll_elm|
# respect user's output-format preferences
if options.output_format == :json and coll_elm.respond_to? :as_json
puts "\n"
pp coll_elm.as_json
puts "\n"
elsif coll_elm.respond_to? :to_string
puts "\n#{coll_elm.to_string}\n"
else
puts "\n#{coll_elm.inspect}\n"
end
end
#
puts "#"*79
end
exit! true
end
# start executing actions
begin
Occi::Cli::Log.info "Executing action #{options.action.inspect} on #{options.resource.inspect} ..."
# call the appropriate helper and then format its output
case options.action
when :list
helper_list options, output
when :describe
helper_describe options, output
when :create
helper_create options, output
when :link
helper_link options, output
when :delete, :unlink
helper_delete options, output
when :trigger
helper_trigger options, output
when :discover
helper_discover options, output
when :update
helper_update options, output
when :refresh
refresh
when :skip, :test, :dry_run
Occi::Cli::Log.info "Just a connection test ..."
else
raise "Unknown action #{options.action.inspect}!"
end
rescue Errno::ECONNREFUSED
# remote server refused our connection attempt(s)
# even though initial connect was successful
Occi::Cli::Log.fatal "Connection refused by #{options.endpoint.inspect}!"
exit!
rescue Errno::ETIMEDOUT, Net::OpenTimeout, Net::ReadTimeout
# connection attempt timed out
Occi::Cli::Log.fatal "Connection to #{options.endpoint.inspect} timed out!"
exit!
rescue => ex
# something went wrong during the execution
# hide the stack trace in non-debug modes
Occi::Cli::Log.fatal "An error occurred! Message: #{ex.message}"
raise ex if options.debug
exit!
end
Occi::Cli::Log.info "OCCI client is shutting down ..."