mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-10 01:17:40 +03:00
Merge branch 'master' of git.opennebula.org:one
This commit is contained in:
commit
dcc181b5f1
11
install.sh
11
install.sh
@ -202,6 +202,7 @@ LIB_DIRS="$LIB_LOCATION/ruby \
|
||||
$LIB_LOCATION/ruby/cloud/econe \
|
||||
$LIB_LOCATION/ruby/cloud/econe/views \
|
||||
$LIB_LOCATION/ruby/cloud/occi \
|
||||
$LIB_LOCATION/ruby/cloud/CloudAuth \
|
||||
$LIB_LOCATION/ruby/onedb \
|
||||
$LIB_LOCATION/tm_commands \
|
||||
$LIB_LOCATION/tm_commands/shared \
|
||||
@ -345,6 +346,7 @@ INSTALL_FILES=(
|
||||
HOOK_FT_FILES:$VAR_LOCATION/remotes/hooks/ft
|
||||
HOOK_NETWORK_FILES:$VAR_LOCATION/remotes/hooks/vnm
|
||||
COMMON_CLOUD_LIB_FILES:$LIB_LOCATION/ruby/cloud
|
||||
CLOUD_AUTH_LIB_FILES:$LIB_LOCATION/ruby/cloud/CloudAuth
|
||||
ECO_LIB_FILES:$LIB_LOCATION/ruby/cloud/econe
|
||||
ECO_LIB_VIEW_FILES:$LIB_LOCATION/ruby/cloud/econe/views
|
||||
ECO_BIN_FILES:$BIN_LOCATION
|
||||
@ -789,10 +791,15 @@ RUBY_OPENNEBULA_LIB_FILES="src/oca/ruby/OpenNebula/Host.rb \
|
||||
|
||||
COMMON_CLOUD_LIB_FILES="src/cloud/common/CloudServer.rb \
|
||||
src/cloud/common/CloudClient.rb \
|
||||
src/cloud/common/CloudAuth.rb
|
||||
src/cloud/common/Configuration.rb"
|
||||
|
||||
COMMON_CLOUD_CLIENT_LIB_FILES="src/cloud/common/CloudClient.rb"
|
||||
|
||||
CLOUD_AUTH_LIB_FILES="src/cloud/common/CloudAuth/BasicCloudAuth.rb \
|
||||
src/cloud/common/CloudAuth/EC2CloudAuth.rb \
|
||||
src/cloud/common/CloudAuth/X509CloudAuth.rb"
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# EC2 Query for OpenNebula
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -926,7 +933,8 @@ SUNSTONE_MODELS_JSON_FILES="src/sunstone/models/OpenNebulaJSON/HostJSON.rb \
|
||||
src/sunstone/models/OpenNebulaJSON/AclJSON.rb \
|
||||
src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb"
|
||||
|
||||
SUNSTONE_TEMPLATE_FILES="src/sunstone/templates/login.html"
|
||||
SUNSTONE_TEMPLATE_FILES="src/sunstone/templates/login.html \
|
||||
src/sunstone/templates/login_x509.html"
|
||||
|
||||
SUNSTONE_VIEWS_FILES="src/sunstone/views/index.erb"
|
||||
|
||||
@ -1007,6 +1015,7 @@ SUNSTONE_PUBLIC_IMAGES_FILES="src/sunstone/public/images/ajax-loader.gif \
|
||||
src/sunstone/public/images/opennebula-sunstone-big.png \
|
||||
src/sunstone/public/images/opennebula-sunstone-small.png \
|
||||
src/sunstone/public/images/panel.png \
|
||||
src/sunstone/public/images/panel_short.png \
|
||||
src/sunstone/public/images/pbar.gif \
|
||||
src/sunstone/public/images/Refresh-icon.png \
|
||||
src/sunstone/public/images/vnc_off.png \
|
||||
|
53
src/cloud/common/CloudAuth.rb
Normal file
53
src/cloud/common/CloudAuth.rb
Normal file
@ -0,0 +1,53 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) #
|
||||
# #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
class CloudAuth
|
||||
AUTH_MODULES = {
|
||||
"basic" => 'BasicCloudAuth',
|
||||
"ec2" => 'EC2CloudAuth',
|
||||
"x509" => 'X509CloudAuth'
|
||||
}
|
||||
|
||||
attr_reader :client, :token
|
||||
|
||||
def initialize(conf)
|
||||
@conf = conf
|
||||
|
||||
if AUTH_MODULES.include?(@conf[:auth])
|
||||
require 'CloudAuth/' + AUTH_MODULES[@conf[:auth]]
|
||||
extend Kernel.const_get(AUTH_MODULES[@conf[:auth]])
|
||||
else
|
||||
raise "Auth module not specified"
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def get_password(username)
|
||||
@oneadmin_client ||= OpenNebula::Client.new(nil, @conf[:one_xmlrpc])
|
||||
|
||||
if @user_pool.nil?
|
||||
@user_pool ||= OpenNebula::UserPool.new(@oneadmin_client)
|
||||
|
||||
rc = @user_pool.info
|
||||
if OpenNebula.is_error?(rc)
|
||||
raise rc.message
|
||||
end
|
||||
end
|
||||
|
||||
return @user_pool["USER[NAME=\"#{username}\"]/PASSWORD"]
|
||||
end
|
||||
end
|
40
src/cloud/common/CloudAuth/BasicCloudAuth.rb
Normal file
40
src/cloud/common/CloudAuth/BasicCloudAuth.rb
Normal file
@ -0,0 +1,40 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) #
|
||||
# #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
module BasicCloudAuth
|
||||
def auth(env, params={})
|
||||
auth = Rack::Auth::Basic::Request.new(env)
|
||||
|
||||
if auth.provided? && auth.basic?
|
||||
username, password = auth.credentials
|
||||
|
||||
if @conf[:hash_passwords]
|
||||
password = Digest::SHA1.hexdigest(password)
|
||||
end
|
||||
|
||||
one_pass = get_password(username)
|
||||
if one_pass && one_pass == password
|
||||
@token = "#{username}:#{password}"
|
||||
@client = Client.new(@token, @conf[:one_xmlrpc], false)
|
||||
return nil
|
||||
else
|
||||
return "Authentication failure"
|
||||
end
|
||||
else
|
||||
return "Basic auth not provided"
|
||||
end
|
||||
end
|
||||
end
|
92
src/cloud/common/CloudAuth/EC2CloudAuth.rb
Normal file
92
src/cloud/common/CloudAuth/EC2CloudAuth.rb
Normal file
@ -0,0 +1,92 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) #
|
||||
# #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
module EC2CloudAuth
|
||||
def auth(env, params={})
|
||||
username = params['AWSAccessKeyId']
|
||||
one_pass = get_password(username)
|
||||
return "Invalid credentials" unless one_pass
|
||||
|
||||
signature = case params['SignatureVersion']
|
||||
when "1" then signature_v1(params.clone,one_pass)
|
||||
when "2" then signature_v2(params.clone,one_pass,env,true,false)
|
||||
end
|
||||
|
||||
if params['Signature'] != signature
|
||||
if params['SignatureVersion']=="2"
|
||||
signature = signature_v2(params.clone,one_pass,env,false,false)
|
||||
if params['Signature'] != signature
|
||||
return "Invalid Credentials"
|
||||
end
|
||||
else
|
||||
return "Invalid Credentials"
|
||||
end
|
||||
end
|
||||
|
||||
@token = "#{username}:#{one_pass}"
|
||||
@client = Client.new(@token, @conf[:one_xmlrpc], false)
|
||||
return nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Calculates signature version 1
|
||||
def signature_v1(params, secret_key, digest='sha1')
|
||||
params.delete('Signature')
|
||||
req_desc = params.sort {|x,y| x[0].downcase <=> y[0].downcase}.to_s
|
||||
|
||||
digest_generator = OpenSSL::Digest::Digest.new(digest)
|
||||
digest = OpenSSL::HMAC.digest(digest_generator, secret_key, req_desc)
|
||||
b64sig = Base64.b64encode(digest)
|
||||
return b64sig.strip
|
||||
end
|
||||
|
||||
# Calculates signature version 2
|
||||
def signature_v2(params, secret_key, env, include_port=true, urlencode=true)
|
||||
params.delete('Signature')
|
||||
params.delete('file')
|
||||
|
||||
server_host = params.delete(:econe_host)
|
||||
server_port = params.delete(:econe_port)
|
||||
if include_port
|
||||
server_str = "#{server_host}:#{server_port}"
|
||||
else
|
||||
server_str = server_host
|
||||
end
|
||||
|
||||
canonical_str = AWS.canonical_string(
|
||||
params,
|
||||
server_str,
|
||||
env['REQUEST_METHOD'])
|
||||
|
||||
# Use the correct signature strength
|
||||
sha_strength = case params['SignatureMethod']
|
||||
when "HmacSHA1" then 'sha1'
|
||||
when "HmacSHA256" then 'sha256'
|
||||
else 'sha1'
|
||||
end
|
||||
|
||||
digest = OpenSSL::Digest::Digest.new(sha_strength)
|
||||
hmac = OpenSSL::HMAC.digest(digest, secret_key, canonical_str)
|
||||
b64hmac = Base64.encode64(hmac).gsub("\n","")
|
||||
|
||||
if urlencode
|
||||
return CGI::escape(b64hmac)
|
||||
else
|
||||
return b64hmac
|
||||
end
|
||||
end
|
||||
end
|
108
src/cloud/common/CloudAuth/X509CloudAuth.rb
Normal file
108
src/cloud/common/CloudAuth/X509CloudAuth.rb
Normal file
@ -0,0 +1,108 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) #
|
||||
# #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
module X509CloudAuth
|
||||
# Gets the username associated with a password
|
||||
# password:: _String_ the password
|
||||
# [return] _Hash_ with the username
|
||||
def get_username(password)
|
||||
@oneadmin_client ||= OpenNebula::Client.new(nil, @conf[:one_xmlrpc])
|
||||
|
||||
if @user_pool.nil?
|
||||
@user_pool ||= OpenNebula::UserPool.new(@oneadmin_client)
|
||||
|
||||
rc = @user_pool.info
|
||||
if OpenNebula.is_error?(rc)
|
||||
raise rc.message
|
||||
end
|
||||
end
|
||||
|
||||
username = @user_pool["USER[PASSWORD=\"#{password}\"]/NAME"]
|
||||
return username if (username != nil)
|
||||
|
||||
# Check if the DN is part of a |-separted multi-DN password
|
||||
user_elts = Array.new
|
||||
@user_pool.each {|e| user_elts << e['PASSWORD']}
|
||||
multiple_users = user_elts.select {|e| e=~ /\|/ }
|
||||
matched = nil
|
||||
multiple_users.each do |e|
|
||||
e.to_s.split('|').each do |w|
|
||||
if (w == password)
|
||||
matched=e
|
||||
break
|
||||
end
|
||||
end
|
||||
break if matched
|
||||
end
|
||||
if matched
|
||||
password = matched.to_s
|
||||
end
|
||||
|
||||
return @user_pool["USER[PASSWORD=\"#{password}\"]/NAME"]
|
||||
end
|
||||
|
||||
def auth(env, params={})
|
||||
failed = 'Authentication failed. '
|
||||
# For https, the web service should be set to include the user cert in the environment.
|
||||
cert_line = env['HTTP_SSL_CLIENT_CERT']
|
||||
cert_line = nil if cert_line == '(null)' # For Apache mod_ssl
|
||||
|
||||
# Use the https credentials for authentication
|
||||
require 'server_auth'
|
||||
while cert_line
|
||||
begin
|
||||
cert_array=cert_line.scan(/([^\s]*)\s/)
|
||||
cert_array = cert_array[2..-2]
|
||||
cert_array.unshift('-----BEGIN CERTIFICATE-----')
|
||||
cert_array.push('-----END CERTIFICATE-----')
|
||||
cert_pem = cert_array.join("\n")
|
||||
cert = OpenSSL::X509::Certificate.new(cert_pem)
|
||||
rescue
|
||||
raise failed + "Could not create X509 certificate from " + cert_line
|
||||
end
|
||||
|
||||
# Password should be DN with whitespace removed.
|
||||
subjectname = cert.subject.to_s.delete("\s")
|
||||
begin
|
||||
username = get_username(subjectname)
|
||||
rescue
|
||||
username = nil
|
||||
end
|
||||
|
||||
break if username
|
||||
|
||||
chain_dn = (!chain_dn ? "" : chain_dn) + "\n" + subjectname
|
||||
chain_index = !chain_index ? 0 : chain_index + 1
|
||||
cert_line = env["HTTP_SSL_CLIENT_CERT_CHAIN_#{chain_index}"]
|
||||
cert_line = nil if cert_line == '(null)' # For Apache mod_ssl
|
||||
end
|
||||
|
||||
if !cert_line
|
||||
msg = ""
|
||||
msg << failed
|
||||
msg << "Username not found in certificate chain "
|
||||
msg << chain_dn if chain_dn
|
||||
raise msg
|
||||
end
|
||||
|
||||
auth = ServerAuth.new
|
||||
|
||||
@token = auth.login_token(username, subjectname, 300)
|
||||
@client = Client.new(@token, @conf[:one_xmlrpc], false)
|
||||
|
||||
return nil
|
||||
end
|
||||
end
|
@ -14,9 +14,8 @@
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
require 'Configuration'
|
||||
require 'OpenNebula'
|
||||
require 'pp'
|
||||
require 'CloudAuth'
|
||||
|
||||
##############################################################################
|
||||
# This class represents a generic Cloud Server using the OpenNebula Cloud
|
||||
@ -28,80 +27,39 @@ class CloudServer
|
||||
# Public attributes
|
||||
##########################################################################
|
||||
attr_reader :config
|
||||
attr_reader :one_client
|
||||
|
||||
# Initializes the Cloud server based on a config file
|
||||
# config_file:: _String_ for the server. MUST include the following
|
||||
# variables:
|
||||
# USER
|
||||
# PASSWORD
|
||||
# AUTH
|
||||
# VM_TYPE
|
||||
# IMAGE_DIR
|
||||
# DATABASE
|
||||
def initialize(config_file)
|
||||
|
||||
# XMLRPC
|
||||
def initialize(config)
|
||||
# --- Load the Cloud Server configuration file ---
|
||||
@config = config
|
||||
@cloud_auth = CloudAuth.new(@config)
|
||||
end
|
||||
|
||||
@config = Configuration.new(config_file)
|
||||
def authenticate(env, params={})
|
||||
@cloud_auth.auth(env, params)
|
||||
end
|
||||
|
||||
if @config[:vm_type] == nil
|
||||
raise "No VM_TYPE defined."
|
||||
end
|
||||
|
||||
@instance_types = Hash.new
|
||||
|
||||
if @config[:vm_type].kind_of?(Array)
|
||||
@config[:vm_type].each {|type|
|
||||
@instance_types[type['NAME']]=type
|
||||
}
|
||||
else
|
||||
@instance_types[@config[:vm_type]['NAME']]=@config[:vm_type]
|
||||
end
|
||||
|
||||
# --- Start an OpenNebula Session ---
|
||||
|
||||
@one_client = Client.new(nil,@config[:one_xmlrpc])
|
||||
@user_pool = UserPool.new(@one_client)
|
||||
def client
|
||||
@cloud_auth.client
|
||||
end
|
||||
|
||||
#
|
||||
# Prints the configuration of the server
|
||||
#
|
||||
def print_configuration
|
||||
def self.print_configuration(config)
|
||||
puts "--------------------------------------"
|
||||
puts " Server configuration "
|
||||
puts "--------------------------------------"
|
||||
pp @config
|
||||
pp config
|
||||
|
||||
puts "--------------------------------------"
|
||||
puts " Registered Instance Types "
|
||||
puts "--------------------------------------"
|
||||
pp @instance_types
|
||||
STDOUT.flush
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# USER and OpenNebula Session Methods
|
||||
###########################################################################
|
||||
|
||||
# Generates an OpenNebula Session for the given user
|
||||
# user:: _Hash_ the user information
|
||||
# [return] an OpenNebula client session
|
||||
def one_client_user(name, password)
|
||||
client = Client.new("dummy:dummy")
|
||||
client.one_auth = "#{name}:#{password}"
|
||||
|
||||
return client
|
||||
end
|
||||
|
||||
# Gets the data associated with a user
|
||||
# name:: _String_ the name of the user
|
||||
# [return] _Hash_ with the user data
|
||||
def get_user_password(name)
|
||||
@user_pool.info
|
||||
return @user_pool["USER[NAME=\"#{name}\"]/PASSWORD"]
|
||||
end
|
||||
|
||||
|
||||
# Finds out if a port is available on ip
|
||||
# ip:: _String_ IP address where the port to check is
|
||||
# port:: _String_ port to find out whether is open
|
||||
@ -123,4 +81,3 @@ class CloudServer
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -15,14 +15,21 @@
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
# OpenNebula sever contact information
|
||||
ONE_XMLRPC=http://localhost:2633/RPC2
|
||||
:one_xmlrpc: http://localhost:2633/RPC2
|
||||
|
||||
# Host and port where econe server will run
|
||||
SERVER=<PUT HERE FQDN OF SERVER>
|
||||
PORT=4567
|
||||
:server: localhost
|
||||
:port: 4567
|
||||
|
||||
# SSL proxy that serves the API (set if is being used)
|
||||
#SSL_SERVER=fqdm.of.the.server
|
||||
#:ssl_server: fqdm.of.the.server
|
||||
|
||||
# Authentication protocol for the econe server:
|
||||
# ec2, default Acess key and Secret key scheme
|
||||
# x509, for x509 certificates based authentication
|
||||
:auth: ec2
|
||||
|
||||
# VM types allowed and its template file (inside templates directory)
|
||||
VM_TYPE=[NAME=m1.small, TEMPLATE=m1.small.erb]
|
||||
:instance_types:
|
||||
:m1.small:
|
||||
:template: m1.small.erb
|
||||
|
@ -15,7 +15,6 @@
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
require 'rubygems'
|
||||
require 'sinatra'
|
||||
require 'erb'
|
||||
require 'time'
|
||||
require 'AWS'
|
||||
@ -62,67 +61,26 @@ class EC2QueryServer < CloudServer
|
||||
|
||||
###########################################################################
|
||||
|
||||
def initialize(config_file,template,views)
|
||||
super(config_file)
|
||||
@config.add_configuration_value("TEMPLATE_LOCATION",template)
|
||||
@config.add_configuration_value("VIEWS",views)
|
||||
|
||||
if @config[:ssl_server]
|
||||
@server_host=@config[:ssl_server]
|
||||
else
|
||||
@server_host=@config[:server]
|
||||
end
|
||||
|
||||
@server_port=@config[:port]
|
||||
|
||||
print_configuration
|
||||
def initialize(config)
|
||||
super(config)
|
||||
end
|
||||
|
||||
def authenticate(env, params)
|
||||
econe_host = @config[:ssl_server]
|
||||
econe_host ||= @config[:server]
|
||||
|
||||
###########################################################################
|
||||
# Authentication functions
|
||||
###########################################################################
|
||||
econe_port = @config[:port]
|
||||
|
||||
# EC2 protocol authentication function
|
||||
# params:: of the request
|
||||
# [return] true if authenticated
|
||||
def authenticate(params,env)
|
||||
password = get_user_password(params['AWSAccessKeyId'])
|
||||
return nil if !password
|
||||
|
||||
signature = case params['SignatureVersion']
|
||||
when "1" then signature_version_1(params.clone, password)
|
||||
when "2" then signature_version_2(params,
|
||||
password,
|
||||
env,
|
||||
true,
|
||||
false)
|
||||
end
|
||||
|
||||
if params['Signature']==signature
|
||||
return one_client_user(params['AWSAccessKeyId'], password)
|
||||
else
|
||||
if params['SignatureVersion']=="2"
|
||||
signature = signature_version_2(params,
|
||||
password,
|
||||
env,
|
||||
false,
|
||||
false)
|
||||
if params['Signature']==signature
|
||||
return one_client_user(params['AWSAccessKeyId'], password)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
params.merge!({:econe_host => econe_host, :econe_port => econe_port})
|
||||
super(env, params)
|
||||
end
|
||||
|
||||
|
||||
###########################################################################
|
||||
# Repository Interface
|
||||
###########################################################################
|
||||
|
||||
def upload_image(params, one_client)
|
||||
image = ImageEC2.new(Image.build_xml, one_client, params['file'])
|
||||
def upload_image(params)
|
||||
image = ImageEC2.new(Image.build_xml, self.client, params['file'])
|
||||
|
||||
template = image.to_one_template
|
||||
if OpenNebula.is_error?(template)
|
||||
@ -140,11 +98,11 @@ class EC2QueryServer < CloudServer
|
||||
return response.result(binding), 200
|
||||
end
|
||||
|
||||
def register_image(params, one_client)
|
||||
def register_image(params)
|
||||
# Get the Image ID
|
||||
tmp, img=params['ImageLocation'].split('-')
|
||||
|
||||
image = Image.new(Image.build_xml(img.to_i), one_client)
|
||||
image = Image.new(Image.build_xml(img.to_i), self.client)
|
||||
|
||||
# Enable the new Image
|
||||
rc = image.info
|
||||
@ -160,9 +118,9 @@ class EC2QueryServer < CloudServer
|
||||
return response.result(binding), 200
|
||||
end
|
||||
|
||||
def describe_images(params, one_client)
|
||||
def describe_images(params)
|
||||
user_flag = OpenNebula::Pool::INFO_GROUP
|
||||
impool = ImagePool.new(one_client, user_flag)
|
||||
impool = ImagePool.new(self.client, user_flag)
|
||||
impool.info
|
||||
|
||||
erb_version = params['Version']
|
||||
@ -175,14 +133,14 @@ class EC2QueryServer < CloudServer
|
||||
# Instance Interface
|
||||
###########################################################################
|
||||
|
||||
def run_instances(params, one_client)
|
||||
def run_instances(params)
|
||||
# Get the instance type and path
|
||||
if params['InstanceType'] != nil
|
||||
instance_type_name = params['InstanceType']
|
||||
instance_type = @instance_types[instance_type_name]
|
||||
instance_type = @config[:instance_types][instance_type_name.to_sym]
|
||||
|
||||
if instance_type != nil
|
||||
path = @config[:template_location] + "/#{instance_type['TEMPLATE']}"
|
||||
path = @config[:template_location] + "/#{instance_type[:template]}"
|
||||
end
|
||||
end
|
||||
|
||||
@ -201,7 +159,7 @@ class EC2QueryServer < CloudServer
|
||||
template_text = template.result(binding)
|
||||
|
||||
# Start the VM.
|
||||
vm = VirtualMachine.new(VirtualMachine.build_xml, one_client)
|
||||
vm = VirtualMachine.new(VirtualMachine.build_xml, self.client)
|
||||
|
||||
rc = vm.allocate(template_text)
|
||||
if OpenNebula::is_error?(rc)
|
||||
@ -219,26 +177,26 @@ class EC2QueryServer < CloudServer
|
||||
return response.result(binding), 200
|
||||
end
|
||||
|
||||
def describe_instances(params, one_client)
|
||||
def describe_instances(params)
|
||||
user_flag = OpenNebula::Pool::INFO_MINE
|
||||
vmpool = VirtualMachinePool.new(one_client, user_flag)
|
||||
vmpool = VirtualMachinePool.new(self.client, user_flag)
|
||||
vmpool.info
|
||||
|
||||
erb_version = params['Version']
|
||||
erb_user_name = params['AWSAccessKeyId']
|
||||
|
||||
|
||||
response = ERB.new(File.read(@config[:views]+"/describe_instances.erb"))
|
||||
return response.result(binding), 200
|
||||
end
|
||||
|
||||
def terminate_instances(params, one_client)
|
||||
def terminate_instances(params)
|
||||
# Get the VM ID
|
||||
vmid=params['InstanceId.1']
|
||||
vmid=params['InstanceId.01'] if !vmid
|
||||
|
||||
tmp, vmid=vmid.split('-') if vmid[0]==?i
|
||||
|
||||
vm = VirtualMachine.new(VirtualMachine.build_xml(vmid),one_client)
|
||||
vm = VirtualMachine.new(VirtualMachine.build_xml(vmid),self.client)
|
||||
rc = vm.info
|
||||
|
||||
return OpenNebula::Error.new('Unsupported'),400 if OpenNebula::is_error?(rc)
|
||||
@ -257,55 +215,6 @@ class EC2QueryServer < CloudServer
|
||||
return response.result(binding), 200
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Calculates signature version 1
|
||||
def signature_version_1(params, secret_key, digest='sha1')
|
||||
params.delete('Signature')
|
||||
req_desc = params.sort {|x,y| x[0].downcase <=> y[0].downcase}.to_s
|
||||
|
||||
digest_generator = OpenSSL::Digest::Digest.new(digest)
|
||||
digest = OpenSSL::HMAC.digest(digest_generator,
|
||||
secret_key,
|
||||
req_desc)
|
||||
b64sig = Base64.b64encode(digest)
|
||||
return b64sig.strip
|
||||
end
|
||||
|
||||
# Calculates signature version 2
|
||||
def signature_version_2(params, secret_key, env, includeport=true, urlencode=true)
|
||||
signature_params = params.reject { |key,value|
|
||||
key=='Signature' or key=='file' }
|
||||
|
||||
if includeport
|
||||
server_str = @server_host + ':' + @server_port
|
||||
else
|
||||
server_str = @server_host
|
||||
end
|
||||
|
||||
canonical_str = AWS.canonical_string(signature_params,
|
||||
server_str,
|
||||
env['REQUEST_METHOD'])
|
||||
|
||||
# Use the correct signature strength
|
||||
sha_strength = case params['SignatureMethod']
|
||||
when "HmacSHA1" then 'sha1'
|
||||
when "HmacSHA256" then 'sha256'
|
||||
else 'sha1'
|
||||
end
|
||||
|
||||
digest = OpenSSL::Digest::Digest.new(sha_strength)
|
||||
b64hmac =
|
||||
Base64.encode64(
|
||||
OpenSSL::HMAC.digest(digest, secret_key, canonical_str)).gsub("\n","")
|
||||
|
||||
if urlencode
|
||||
return CGI::escape(b64hmac)
|
||||
else
|
||||
return b64hmac
|
||||
end
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# Helper functions
|
||||
###########################################################################
|
||||
|
@ -42,37 +42,54 @@ require 'rubygems'
|
||||
require 'sinatra'
|
||||
|
||||
require 'EC2QueryServer'
|
||||
require 'Configuration'
|
||||
|
||||
include OpenNebula
|
||||
|
||||
##############################################################################
|
||||
# Parse Configuration file
|
||||
##############################################################################
|
||||
begin
|
||||
$econe_server = EC2QueryServer.new(CONFIGURATION_FILE,
|
||||
TEMPLATE_LOCATION, VIEWS_LOCATION)
|
||||
conf = YAML.load_file(CONFIGURATION_FILE)
|
||||
rescue Exception => e
|
||||
puts "Error starting server: #{e}"
|
||||
exit(-1)
|
||||
puts "Error parsing config file #{CONFIGURATION_FILE}: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
if CloudServer.is_port_open?($econe_server.config[:server],
|
||||
$econe_server.config[:port])
|
||||
puts "Port busy, please shutdown the service or move econe server port."
|
||||
exit
|
||||
end
|
||||
conf[:template_location] = TEMPLATE_LOCATION
|
||||
conf[:views] = VIEWS_LOCATION
|
||||
|
||||
CloudServer.print_configuration(conf)
|
||||
|
||||
##############################################################################
|
||||
# Sinatra Configuration
|
||||
##############################################################################
|
||||
set :host, $econe_server.config[:server]
|
||||
set :port, $econe_server.config[:port]
|
||||
set :config, conf
|
||||
set :host, settings.config[:server]
|
||||
set :port, settings.config[:port]
|
||||
|
||||
if CloudServer.is_port_open?(settings.config[:server],
|
||||
settings.config[:port])
|
||||
puts "Port busy, please shutdown the service or move econe server port."
|
||||
exit 1
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
# Actions
|
||||
##############################################################################
|
||||
|
||||
before do
|
||||
@client = $econe_server.authenticate(params,env)
|
||||
|
||||
if @client.nil?
|
||||
@econe_server = EC2QueryServer.new(settings.config)
|
||||
|
||||
begin
|
||||
result = @econe_server.authenticate(request.env, params)
|
||||
rescue Exception => e
|
||||
# Add a log message
|
||||
error 500, error_xml("AuthFailure", 0)
|
||||
end
|
||||
|
||||
if result
|
||||
# Add a log message
|
||||
error 400, error_xml("AuthFailure", 0)
|
||||
end
|
||||
end
|
||||
@ -80,7 +97,7 @@ end
|
||||
helpers do
|
||||
def error_xml(code,id)
|
||||
message = ''
|
||||
|
||||
|
||||
case code
|
||||
when 'AuthFailure'
|
||||
message = 'User not authorized'
|
||||
@ -88,45 +105,44 @@ helpers do
|
||||
message = 'Specified AMI ID does not exist'
|
||||
when 'Unsupported'
|
||||
message = 'The instance type or feature is not supported in your requested Availability Zone.'
|
||||
else
|
||||
else
|
||||
message = code
|
||||
end
|
||||
|
||||
|
||||
xml = "<Response><Errors><Error><Code>"+
|
||||
code +
|
||||
"</Code><Message>" +
|
||||
message +
|
||||
"</Message></Error></Errors><RequestID>" +
|
||||
id.to_s +
|
||||
code +
|
||||
"</Code><Message>" +
|
||||
message +
|
||||
"</Message></Error></Errors><RequestID>" +
|
||||
id.to_s +
|
||||
"</RequestID></Response>"
|
||||
|
||||
return xml
|
||||
end
|
||||
|
||||
return xml
|
||||
end
|
||||
end
|
||||
|
||||
post '/' do
|
||||
do_http_request(params, @client)
|
||||
do_http_request(params)
|
||||
end
|
||||
|
||||
get '/' do
|
||||
do_http_request(params, @client)
|
||||
do_http_request(params)
|
||||
end
|
||||
|
||||
def do_http_request(params, client)
|
||||
|
||||
def do_http_request(params)
|
||||
case params['Action']
|
||||
when 'UploadImage'
|
||||
result,rc = $econe_server.upload_image(params, client)
|
||||
result,rc = @econe_server.upload_image(params)
|
||||
when 'RegisterImage'
|
||||
result,rc = $econe_server.register_image(params, client)
|
||||
result,rc = @econe_server.register_image(params)
|
||||
when 'DescribeImages'
|
||||
result,rc = $econe_server.describe_images(params, client)
|
||||
result,rc = @econe_server.describe_images(params)
|
||||
when 'RunInstances'
|
||||
result,rc = $econe_server.run_instances(params, client)
|
||||
result,rc = @econe_server.run_instances(params)
|
||||
when 'DescribeInstances'
|
||||
result,rc = $econe_server.describe_instances(params, client)
|
||||
result,rc = @econe_server.describe_instances(params)
|
||||
when 'TerminateInstances'
|
||||
result,rc = $econe_server.terminate_instances(params, client)
|
||||
result,rc = @econe_server.terminate_instances(params)
|
||||
end
|
||||
|
||||
if OpenNebula::is_error?(result)
|
||||
@ -135,5 +151,5 @@ def do_http_request(params, client)
|
||||
|
||||
headers['Content-Type'] = 'application/xml'
|
||||
|
||||
result
|
||||
result
|
||||
end
|
||||
|
@ -14,21 +14,31 @@
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
# OpenNebula server contact information
|
||||
ONE_XMLRPC=http://localhost:2633/RPC2
|
||||
# OpenNebula sever contact information
|
||||
:one_xmlrpc: http://localhost:2633/RPC2
|
||||
|
||||
# Host and port where the occi server will run
|
||||
SERVER=<FQDN OF OCCI SERVER>
|
||||
PORT=4567
|
||||
# Host and port where OCCI server will run
|
||||
:server: localhost
|
||||
:port: 4567
|
||||
|
||||
# SSL proxy that serves the API (set if is being used)
|
||||
#SSL_SERVER=https://localhost:443
|
||||
#:ssl_server: fqdm.of.the.server
|
||||
|
||||
# Configuration for OpenNebula's Virtual Networks
|
||||
BRIDGE=<NAME OF DEFAULT BRIDGE>
|
||||
#:bridge: NAME_OF_DEFAULT_BRIDGE
|
||||
|
||||
# Authentication protocol for the OCCI server:
|
||||
# basic, for OpenNebula's user-password scheme
|
||||
# x509, for x509 certificates based authentication
|
||||
:auth: basic
|
||||
|
||||
# VM types allowed and its template file (inside templates directory)
|
||||
VM_TYPE=[NAME=custom, TEMPLATE=custom.erb]
|
||||
VM_TYPE=[NAME=small, TEMPLATE=small.erb]
|
||||
VM_TYPE=[NAME=medium, TEMPLATE=medium.erb]
|
||||
VM_TYPE=[NAME=large, TEMPLATE=large.erb]
|
||||
:instance_types:
|
||||
:custom:
|
||||
:template: custom.erb
|
||||
:small:
|
||||
:template: small.erb
|
||||
:medium:
|
||||
:template: medium.erb
|
||||
:large:
|
||||
:template: large.erb
|
||||
|
@ -15,12 +15,9 @@
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
# Common cloud libs
|
||||
require 'rubygems'
|
||||
require 'sinatra'
|
||||
require 'CloudServer'
|
||||
|
||||
# OCA
|
||||
require 'OpenNebula'
|
||||
include OpenNebula
|
||||
|
||||
# OCCI libs
|
||||
@ -43,29 +40,13 @@ class OCCIServer < CloudServer
|
||||
# Server initializer
|
||||
# config_file:: _String_ path of the config file
|
||||
# template:: _String_ path to the location of the templates
|
||||
def initialize(config_file,template)
|
||||
super(config_file)
|
||||
def initialize(config)
|
||||
super(config)
|
||||
|
||||
@config.add_configuration_value("TEMPLATE_LOCATION",template)
|
||||
|
||||
if @config[:ssl_server]
|
||||
@base_url=@config[:ssl_server]
|
||||
if config[:ssl_server]
|
||||
@base_url=config[:ssl_server]
|
||||
else
|
||||
@base_url="http://#{@config[:server]}:#{@config[:port]}"
|
||||
end
|
||||
|
||||
print_configuration
|
||||
end
|
||||
|
||||
# Retrieve a client with the user credentials
|
||||
# requestenv:: _Hash_ Hash containing the environment of the request
|
||||
# [return] _Client_ client with the user credentials
|
||||
def get_client(requestenv)
|
||||
auth = Rack::Auth::Basic::Request.new(requestenv)
|
||||
if auth
|
||||
return one_client_user(auth.credentials[0], auth.credentials[1])
|
||||
else
|
||||
return nil
|
||||
@base_url="http://#{config[:server]}:#{config[:port]}"
|
||||
end
|
||||
end
|
||||
|
||||
@ -92,13 +73,8 @@ class OCCIServer < CloudServer
|
||||
# --- Get User's VMs ---
|
||||
user_flag = -1
|
||||
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
vmpool = VirtualMachinePoolOCCI.new(
|
||||
one_client,
|
||||
self.client,
|
||||
user_flag)
|
||||
|
||||
# --- Prepare XML Response ---
|
||||
@ -124,13 +100,8 @@ class OCCIServer < CloudServer
|
||||
# --- Get User's VNETs ---
|
||||
user_flag = -1
|
||||
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
network_pool = VirtualNetworkPoolOCCI.new(
|
||||
one_client,
|
||||
self.client,
|
||||
user_flag)
|
||||
|
||||
# --- Prepare XML Response ---
|
||||
@ -155,13 +126,8 @@ class OCCIServer < CloudServer
|
||||
# --- Get User's Images ---
|
||||
user_flag = -1
|
||||
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
image_pool = ImagePoolOCCI.new(
|
||||
one_client,
|
||||
self.client,
|
||||
user_flag)
|
||||
|
||||
# --- Prepare XML Response ---
|
||||
@ -193,16 +159,11 @@ class OCCIServer < CloudServer
|
||||
# [return] _String_,_Integer_ COMPUTE Representation or error, status code
|
||||
def post_compute(request)
|
||||
# --- Create the new Instance ---
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
vm = VirtualMachineOCCI.new(
|
||||
VirtualMachine.build_xml,
|
||||
one_client,
|
||||
self.client,
|
||||
request.body.read,
|
||||
@instance_types,
|
||||
@config[:instance_types],
|
||||
@config[:template_location])
|
||||
|
||||
# --- Generate the template and Allocate the new Instance ---
|
||||
@ -223,14 +184,9 @@ class OCCIServer < CloudServer
|
||||
# status code
|
||||
def get_compute(request, params)
|
||||
# --- Get the VM ---
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
vm = VirtualMachineOCCI.new(
|
||||
VirtualMachine.build_xml(params[:id]),
|
||||
one_client)
|
||||
self.client)
|
||||
|
||||
# --- Prepare XML Response ---
|
||||
rc = vm.info
|
||||
@ -253,14 +209,9 @@ class OCCIServer < CloudServer
|
||||
# status code
|
||||
def delete_compute(request, params)
|
||||
# --- Get the VM ---
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
vm = VirtualMachineOCCI.new(
|
||||
VirtualMachine.build_xml(params[:id]),
|
||||
one_client)
|
||||
self.client)
|
||||
|
||||
rc = vm.info
|
||||
return rc, 404 if OpenNebula::is_error?(rc)
|
||||
@ -278,14 +229,9 @@ class OCCIServer < CloudServer
|
||||
# status code
|
||||
def put_compute(request, params)
|
||||
# --- Get the VM ---
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
vm = VirtualMachineOCCI.new(
|
||||
VirtualMachine.build_xml(params[:id]),
|
||||
one_client)
|
||||
self.client)
|
||||
|
||||
rc = vm.info
|
||||
return rc, 400 if OpenNebula.is_error?(rc)
|
||||
@ -349,14 +295,9 @@ class OCCIServer < CloudServer
|
||||
# [return] _String_,_Integer_ Network Representation or error, status code
|
||||
def post_network(request)
|
||||
# --- Create the new Instance ---
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
network = VirtualNetworkOCCI.new(
|
||||
VirtualNetwork.build_xml,
|
||||
one_client,
|
||||
self.client,
|
||||
request.body,
|
||||
@config[:bridge])
|
||||
|
||||
@ -377,15 +318,9 @@ class OCCIServer < CloudServer
|
||||
# [return] _String_,_Integer_ NETWORK occi representation or error,
|
||||
# status code
|
||||
def get_network(request, params)
|
||||
# --- Get the VNET ---
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
network = VirtualNetworkOCCI.new(
|
||||
VirtualNetwork.build_xml(params[:id]),
|
||||
one_client)
|
||||
self.client)
|
||||
|
||||
# --- Prepare XML Response ---
|
||||
rc = network.info
|
||||
@ -406,15 +341,9 @@ class OCCIServer < CloudServer
|
||||
# [return] _String_,_Integer_ Delete confirmation msg or error,
|
||||
# status code
|
||||
def delete_network(request, params)
|
||||
# --- Get the VNET ---
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
network = VirtualNetworkOCCI.new(
|
||||
VirtualNetwork.build_xml(params[:id]),
|
||||
one_client)
|
||||
self.client)
|
||||
|
||||
rc = network.info
|
||||
return rc, 404 if OpenNebula::is_error?(rc)
|
||||
@ -433,15 +362,10 @@ class OCCIServer < CloudServer
|
||||
def put_network(request, params)
|
||||
xmldoc = XMLElement.build_xml(request.body, 'NETWORK')
|
||||
vnet_info = XMLElement.new(xmldoc) if xmldoc != nil
|
||||
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
vnet = VirtualNetworkOCCI.new(
|
||||
VirtualNetwork.build_xml(params[:id]),
|
||||
one_client)
|
||||
self.client)
|
||||
|
||||
rc = vnet.info
|
||||
return rc, 400 if OpenNebula.is_error?(rc)
|
||||
@ -474,11 +398,6 @@ class OCCIServer < CloudServer
|
||||
error = OpenNebula::Error.new(error_msg)
|
||||
return error, 400
|
||||
end
|
||||
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
# --- Create and Add the new Image ---
|
||||
occixml = request.params['occixml']
|
||||
@ -486,7 +405,7 @@ class OCCIServer < CloudServer
|
||||
|
||||
image = ImageOCCI.new(
|
||||
Image.build_xml,
|
||||
one_client,
|
||||
self.client,
|
||||
occixml,
|
||||
request.params['file'])
|
||||
|
||||
@ -508,14 +427,9 @@ class OCCIServer < CloudServer
|
||||
# status code
|
||||
def get_storage(request, params)
|
||||
# --- Get the Image ---
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
image = ImageOCCI.new(
|
||||
Image.build_xml(params[:id]),
|
||||
one_client)
|
||||
self.client)
|
||||
|
||||
rc = image.info
|
||||
|
||||
@ -537,14 +451,9 @@ class OCCIServer < CloudServer
|
||||
# status code
|
||||
def delete_storage(request, params)
|
||||
# --- Get the Image ---
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
image = ImageOCCI.new(
|
||||
Image.build_xml(params[:id]),
|
||||
one_client)
|
||||
self.client)
|
||||
|
||||
rc = image.info
|
||||
return rc, 404 if OpenNebula::is_error?(rc)
|
||||
@ -563,15 +472,10 @@ class OCCIServer < CloudServer
|
||||
def put_storage(request, params)
|
||||
xmldoc = XMLElement.build_xml(request.body, 'STORAGE')
|
||||
image_info = XMLElement.new(xmldoc) if xmldoc != nil
|
||||
|
||||
one_client = get_client(request.env)
|
||||
if !one_client
|
||||
return "No authorization data present", 401
|
||||
end
|
||||
|
||||
image = ImageOCCI.new(
|
||||
Image.build_xml(params[:id]),
|
||||
one_client)
|
||||
self.client)
|
||||
|
||||
rc = image.info
|
||||
return rc, 400 if OpenNebula.is_error?(rc)
|
||||
|
@ -77,8 +77,8 @@ class VirtualMachineOCCI < VirtualMachine
|
||||
if @vm_info != nil
|
||||
itype = @vm_info['INSTANCE_TYPE']
|
||||
|
||||
if itype != nil and types[itype] != nil
|
||||
@template = base + "/#{types[itype]['TEMPLATE']}"
|
||||
if itype != nil and types[itype.to_sym] != nil
|
||||
@template = base + "/#{types[itype.to_sym][:template]}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -43,35 +43,56 @@ $: << RUBY_LIB_LOCATION+"/cloud" # For the Repository Manager
|
||||
################################################
|
||||
require 'rubygems'
|
||||
require 'sinatra'
|
||||
require 'OCCIServer'
|
||||
|
||||
require 'OpenNebula'
|
||||
require 'OCCIServer'
|
||||
|
||||
include OpenNebula
|
||||
|
||||
##############################################################################
|
||||
# Parse Configuration file
|
||||
##############################################################################
|
||||
begin
|
||||
$occi_server = OCCIServer.new(CONFIGURATION_FILE, TEMPLATE_LOCATION)
|
||||
conf = YAML.load_file(CONFIGURATION_FILE)
|
||||
rescue Exception => e
|
||||
puts "Error starting server: #{e}"
|
||||
exit(-1)
|
||||
puts "Error parsing config file #{CONFIGURATION_FILE}: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
if CloudServer.is_port_open?($occi_server.config[:server],
|
||||
$occi_server.config[:port])
|
||||
puts "Port busy, please shutdown the service or move occi server port."
|
||||
exit
|
||||
end
|
||||
conf[:template_location] = TEMPLATE_LOCATION
|
||||
|
||||
CloudServer.print_configuration(conf)
|
||||
|
||||
##############################################################################
|
||||
# Sinatra Configuration
|
||||
##############################################################################
|
||||
set :host, $occi_server.config[:server]
|
||||
set :port, $occi_server.config[:port]
|
||||
set :config, conf
|
||||
|
||||
if CloudServer.is_port_open?(settings.config[:server],
|
||||
settings.config[:port])
|
||||
puts "Port busy, please shutdown the service or move occi server port."
|
||||
exit
|
||||
end
|
||||
|
||||
set :host, settings.config[:server]
|
||||
set :port, settings.config[:port]
|
||||
|
||||
##############################################################################
|
||||
# Helpers
|
||||
##############################################################################
|
||||
|
||||
before do
|
||||
@occi_server = OCCIServer.new(settings.config)
|
||||
begin
|
||||
result = @occi_server.authenticate(request.env)
|
||||
rescue Exception => e
|
||||
error 500, e.message
|
||||
end
|
||||
|
||||
if result
|
||||
error 401, result
|
||||
end
|
||||
end
|
||||
|
||||
# Response treatment
|
||||
helpers do
|
||||
def treat_response(result,rc)
|
||||
@ -93,32 +114,32 @@ end
|
||||
###################################################
|
||||
|
||||
post '/compute' do
|
||||
result,rc = $occi_server.post_compute(request)
|
||||
result,rc = @occi_server.post_compute(request)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
get '/compute' do
|
||||
result,rc = $occi_server.get_computes(request)
|
||||
result,rc = @occi_server.get_computes(request)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
post '/network' do
|
||||
result,rc = $occi_server.post_network(request)
|
||||
result,rc = @occi_server.post_network(request)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
get '/network' do
|
||||
result,rc = $occi_server.get_networks(request)
|
||||
result,rc = @occi_server.get_networks(request)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
post '/storage' do
|
||||
result,rc = $occi_server.post_storage(request)
|
||||
result,rc = @occi_server.post_storage(request)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
get '/storage' do
|
||||
result,rc = $occi_server.get_storages(request)
|
||||
result,rc = @occi_server.get_storages(request)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
@ -127,46 +148,46 @@ end
|
||||
###################################################
|
||||
|
||||
get '/compute/:id' do
|
||||
result,rc = $occi_server.get_compute(request, params)
|
||||
result,rc = @occi_server.get_compute(request, params)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
delete '/compute/:id' do
|
||||
result,rc = $occi_server.delete_compute(request, params)
|
||||
result,rc = @occi_server.delete_compute(request, params)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
put '/compute/:id' do
|
||||
result,rc = $occi_server.put_compute(request, params)
|
||||
result,rc = @occi_server.put_compute(request, params)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
get '/network/:id' do
|
||||
result,rc = $occi_server.get_network(request, params)
|
||||
result,rc = @occi_server.get_network(request, params)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
delete '/network/:id' do
|
||||
result,rc = $occi_server.delete_network(request, params)
|
||||
result,rc = @occi_server.delete_network(request, params)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
put '/network/:id' do
|
||||
result,rc = $occi_server.put_network(request, params)
|
||||
result,rc = @occi_server.put_network(request, params)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
get '/storage/:id' do
|
||||
result,rc = $occi_server.get_storage(request, params)
|
||||
result,rc = @occi_server.get_storage(request, params)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
delete '/storage/:id' do
|
||||
result,rc = $occi_server.delete_storage(request, params)
|
||||
result,rc = @occi_server.delete_storage(request, params)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
||||
put '/storage/:id' do
|
||||
result,rc = $occi_server.put_storage(request, params)
|
||||
result,rc = @occi_server.put_storage(request, params)
|
||||
treat_response(result,rc)
|
||||
end
|
||||
|
@ -19,11 +19,6 @@ module OZones
|
||||
class ApacheWritter
|
||||
def initialize(file_path)
|
||||
@file_path = file_path
|
||||
|
||||
File.open(@file_path, 'w') {|f|
|
||||
f.flock(File::LOCK_EX)
|
||||
f.write(htaccess)
|
||||
}
|
||||
end
|
||||
|
||||
def update
|
||||
|
@ -226,7 +226,7 @@ class OzonesServer
|
||||
mandatory_params = [:onename, :onepass, :endpoint, :name]
|
||||
|
||||
mandatory_params.each { |param|
|
||||
if !vdc_data[param]
|
||||
if !zone_data[param]
|
||||
return [400, OZones::Error.new(
|
||||
"Error: Couldn't create resource #{kind}. " +
|
||||
"Mandatory attribute '#{param}' is missing.").to_json]
|
||||
|
@ -19,13 +19,13 @@
|
||||
|
||||
if [ -z "$ONE_LOCATION" ]; then
|
||||
SUNSTONE_PID=/var/run/one/sunstone.pid
|
||||
SUNSTONE_SERVER=/usr/lib/one/sunstone/config.ru
|
||||
SUNSTONE_SERVER=/usr/lib/one/sunstone/sunstone-server.rb
|
||||
SUNSTONE_LOCK_FILE=/var/lock/one/.sunstone.lock
|
||||
SUNSTONE_LOG=/var/log/one/sunstone.log
|
||||
SUNSTONE_CONF=/etc/one/sunstone-server.conf
|
||||
else
|
||||
SUNSTONE_PID=$ONE_LOCATION/var/sunstone.pid
|
||||
SUNSTONE_SERVER=$ONE_LOCATION/lib/sunstone/config.ru
|
||||
SUNSTONE_SERVER=$ONE_LOCATION/lib/sunstone/sunstone-server.rb
|
||||
SUNSTONE_LOCK_FILE=$ONE_LOCATION/var/.sunstone.lock
|
||||
SUNSTONE_LOG=$ONE_LOCATION/var/sunstone.log
|
||||
SUNSTONE_CONF=$ONE_LOCATION/etc/sunstone-server.conf
|
||||
@ -56,23 +56,16 @@ start()
|
||||
echo "Can not find $SUNSTONE_SERVER."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source $SUNSTONE_CONF
|
||||
|
||||
lsof -i:$PORT &> /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "The port $PORT is being used. Please specify a different one."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start the sunstone daemon
|
||||
touch $SUNSTONE_LOCK_FILE
|
||||
rackup $SUNSTONE_SERVER -s thin -p $PORT -o $HOST \
|
||||
-P $SUNSTONE_PID &> $SUNSTONE_LOG &
|
||||
ruby $SUNSTONE_SERVER > $SUNSTONE_LOG 2>&1 &
|
||||
LASTPID=$!
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error executing $SUNSTONE_SERVER, please check the log $SUNSTONE_LOG"
|
||||
exit 1
|
||||
else
|
||||
echo $LASTPID > $SUNSTONE_PID
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
@ -83,7 +76,7 @@ start()
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "sunstone-server listening on $HOST:$PORT"
|
||||
echo "sunstone-server started"
|
||||
}
|
||||
|
||||
#
|
||||
|
@ -1,7 +1,12 @@
|
||||
# OpenNebula sever contact information
|
||||
:one_xmlrpc: http://localhost:2633/RPC2
|
||||
|
||||
# Server Configuration
|
||||
HOST=127.0.0.1
|
||||
PORT=9869
|
||||
:host: 127.0.0.1
|
||||
:port: 9869
|
||||
|
||||
:auth: basic
|
||||
|
||||
# VNC Configuration
|
||||
VNC_PROXY_BASE_PORT=29876
|
||||
NOVNC_PATH=
|
||||
:vnc_proxy_base_port: 29876
|
||||
:novnc_path:
|
||||
|
@ -23,37 +23,8 @@ class SunstoneServer
|
||||
# FLAG that will filter the elements retrieved from the Pools
|
||||
POOL_FILTER = Pool::INFO_GROUP
|
||||
|
||||
def initialize(username, password)
|
||||
# TBD one_client_user(name) from CloudServer
|
||||
@client = Client.new("dummy:dummy")
|
||||
@client.one_auth = "#{username}:#{password}"
|
||||
end
|
||||
|
||||
############################################################################
|
||||
#
|
||||
############################################################################
|
||||
def self.authorize(user="", sha1_pass="")
|
||||
if user.empty? || sha1_pass.empty?
|
||||
return [401, false]
|
||||
end
|
||||
|
||||
# TBD get_user_password(name) from CloudServer
|
||||
user_pool = UserPool.new(Client.new)
|
||||
rc = user_pool.info
|
||||
if OpenNebula.is_error?(rc)
|
||||
return [500, false]
|
||||
end
|
||||
|
||||
user_pass = user_pool["USER[NAME=\"#{user}\"]/PASSWORD"]
|
||||
user_id = user_pool["USER[NAME=\"#{user}\"]/ID"]
|
||||
user_gid = user_pool["USER[NAME=\"#{user}\"]/GID"]
|
||||
user_gname = user_pool["USER[NAME=\"#{user}\"]/GNAME"]
|
||||
|
||||
if user_pass == sha1_pass
|
||||
return [204, [user_id, user_gid, user_gname]]
|
||||
else
|
||||
return [401, nil]
|
||||
end
|
||||
def initialize(token, xmlrpc)
|
||||
@client = Client.new(token, xmlrpc, false)
|
||||
end
|
||||
|
||||
############################################################################
|
||||
|
BIN
src/sunstone/public/images/panel_short.png
Normal file
BIN
src/sunstone/public/images/panel_short.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
@ -36,6 +36,7 @@ end
|
||||
SUNSTONE_ROOT_DIR = File.dirname(__FILE__)
|
||||
|
||||
$: << RUBY_LIB_LOCATION
|
||||
$: << RUBY_LIB_LOCATION+'/cloud'
|
||||
$: << SUNSTONE_ROOT_DIR+'/models'
|
||||
|
||||
##############################################################################
|
||||
@ -45,16 +46,23 @@ require 'rubygems'
|
||||
require 'sinatra'
|
||||
require 'erb'
|
||||
|
||||
require 'cloud/Configuration'
|
||||
require 'CloudAuth'
|
||||
require 'SunstoneServer'
|
||||
require 'SunstonePlugins'
|
||||
|
||||
set :config, Configuration.new(CONFIGURATION_FILE)
|
||||
begin
|
||||
conf = YAML.load_file(CONFIGURATION_FILE)
|
||||
conf[:hash_passwords] = true
|
||||
rescue Exception => e
|
||||
puts "Error parsing config file #{CONFIGURATION_FILE}: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
# Sinatra Configuration
|
||||
##############################################################################
|
||||
use Rack::Session::Pool, :key => 'sunstone'
|
||||
set :config, conf
|
||||
set :host, settings.config[:host]
|
||||
set :port, settings.config[:port]
|
||||
|
||||
@ -67,32 +75,40 @@ helpers do
|
||||
end
|
||||
|
||||
def build_session
|
||||
auth = Rack::Auth::Basic::Request.new(request.env)
|
||||
if auth.provided? && auth.basic? && auth.credentials
|
||||
user = auth.credentials[0]
|
||||
sha1_pass = Digest::SHA1.hexdigest(auth.credentials[1])
|
||||
cloud_auth = CloudAuth.new(settings.config)
|
||||
|
||||
rc = SunstoneServer.authorize(user, sha1_pass)
|
||||
if rc[1]
|
||||
session[:user] = user
|
||||
session[:user_id] = rc[1][0]
|
||||
session[:user_gid] = rc[1][1]
|
||||
session[:user_gname] = rc[1][2]
|
||||
session[:password] = sha1_pass
|
||||
session[:ip] = request.ip
|
||||
session[:remember] = params[:remember]
|
||||
|
||||
if params[:remember]
|
||||
env['rack.session.options'][:expire_after] = 30*60*60*24
|
||||
end
|
||||
|
||||
return [204, ""]
|
||||
else
|
||||
return [rc.first, ""]
|
||||
end
|
||||
begin
|
||||
result = cloud_auth.auth(request.env, params)
|
||||
rescue Exception => e
|
||||
error 500, e.message
|
||||
end
|
||||
|
||||
return [401, ""]
|
||||
if result
|
||||
return [401, ""]
|
||||
else
|
||||
user_id = OpenNebula::User::SELF
|
||||
user = OpenNebula::User.new_with_id(user_id, cloud_auth.client)
|
||||
|
||||
rc = user.info
|
||||
if OpenNebula.is_error?(rc)
|
||||
# Add a log message
|
||||
return [500, ""]
|
||||
end
|
||||
|
||||
session[:user] = user['NAME']
|
||||
session[:user_id] = user['ID']
|
||||
session[:user_gid] = user['GID']
|
||||
session[:user_gname] = user['GNAME']
|
||||
session[:token] = cloud_auth.token
|
||||
session[:ip] = request.ip
|
||||
session[:remember] = params[:remember]
|
||||
|
||||
if params[:remember]
|
||||
env['rack.session.options'][:expire_after] = 30*60*60*24
|
||||
end
|
||||
|
||||
return [204, ""]
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_session
|
||||
@ -105,7 +121,9 @@ before do
|
||||
unless request.path=='/login' || request.path=='/'
|
||||
halt 401 unless authorized?
|
||||
|
||||
@SunstoneServer = SunstoneServer.new(session[:user], session[:password])
|
||||
@SunstoneServer = SunstoneServer.new(
|
||||
session[:token],
|
||||
settings.config[:one_xmlrpc])
|
||||
end
|
||||
end
|
||||
|
||||
@ -125,9 +143,10 @@ end
|
||||
# HTML Requests
|
||||
##############################################################################
|
||||
get '/' do
|
||||
return File.read(File.dirname(__FILE__)+
|
||||
'/templates/login.html') unless authorized?
|
||||
|
||||
if !authorized?
|
||||
templ = settings.config[:auth]=="basic"? "login.html" : "login_x509.html"
|
||||
return File.read(File.dirname(__FILE__)+'/templates/'+templ)
|
||||
end
|
||||
time = Time.now + 60
|
||||
response.set_cookie("one-user",
|
||||
:value=>"#{session[:user]}",
|
||||
@ -146,7 +165,10 @@ get '/' do
|
||||
end
|
||||
|
||||
get '/login' do
|
||||
File.read(SUNSTONE_ROOT_DIR+'/templates/login.html')
|
||||
if !authorized?
|
||||
templ = settings.confing[:auth]=="basic"? "login.html" : "login_x509.html"
|
||||
return File.read(File.dirname(__FILE__)+'/templates/'+templ)
|
||||
end
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
|
47
src/sunstone/templates/login_x509.html
Normal file
47
src/sunstone/templates/login_x509.html
Normal file
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>OpenNebula Sunstone Login</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/login.css" />
|
||||
|
||||
<!-- Vendor Libraries -->
|
||||
<script type="text/javascript" src="vendor/jQuery/jquery-1.4.4.min.js"></script>
|
||||
<!-- End Vendor Libraries -->
|
||||
|
||||
<script type="text/javascript" src="js/opennebula.js"></script>
|
||||
<script type="text/javascript" src="js/login.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<div id="header">
|
||||
<div id="logo">
|
||||
The OpenNebula Cloud Operations Center
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="wrapper">
|
||||
<div id="logo_sunstone">
|
||||
</div>
|
||||
|
||||
<div id="auth_error" class="error_message">
|
||||
Invalid username or password
|
||||
</div>
|
||||
<div id="one_error" class="error_message">
|
||||
OpenNebula is not running
|
||||
</div>
|
||||
|
||||
<form id="login_form">
|
||||
<div class="border" id="login" style='height:169px;background:url("../images/panel_short.png") no-repeat scroll center transparent'>
|
||||
<div class="content">
|
||||
<input style="float:left;" type="submit" id="login_btn" value="" />
|
||||
<input type="checkbox" id="check_remember" />
|
||||
<label id="label_remember" for="check_remember">Remember me</label>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user