1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-26 06:50:09 +03:00

First commit of OpenNebula OCCI implementation

git-svn-id: http://svn.opennebula.org/one/trunk@783 3034c82b-c49b-4eb3-8279-a7acafdc01c0
This commit is contained in:
Constantino Vázquez Blanco 2009-09-03 18:10:55 +00:00
parent fc85c54245
commit 8b717585d5
17 changed files with 1718 additions and 1 deletions

View File

@ -128,12 +128,14 @@ ETC_DIRS="$ETC_LOCATION/im_kvm \
$ETC_LOCATION/tm_ssh \
$ETC_LOCATION/tm_dummy \
$ETC_LOCATION/hm \
$ETC_LOCATION/ec2query_templates"
$ETC_LOCATION/ec2query_templates \
$ETC_LOCATION/occi_templates"
LIB_DIRS="$LIB_LOCATION/im_probes \
$LIB_LOCATION/ruby \
$LIB_LOCATION/ruby/OpenNebula \
$LIB_LOCATION/ruby/econe \
$LIB_LOCATION/ruby/occi \
$LIB_LOCATION/tm_commands \
$LIB_LOCATION/tm_commands/nfs \
$LIB_LOCATION/tm_commands/ssh \
@ -163,6 +165,8 @@ INSTALL_FILES[11]="TM_EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples/tm"
INSTALL_FILES[12]="HOOK_SHARE_FILES:$SHARE_LOCATION/hooks"
INSTALL_FILES[13]="ECO_LIB_FILES:$LIB_LOCATION/ruby/econe"
INSTALL_FILES[14]="ECO_BIN_FILES:$BIN_LOCATION"
INSTALL_FILES[15]="OCCI_LIB_FILES:$LIB_LOCATION/ruby/occi"
INSTALL_FILES[16]="OCCI_BIN_FILES:$BIN_LOCATION"
INSTALL_ETC_FILES[0]="ETC_FILES:$ETC_LOCATION"
INSTALL_ETC_FILES[1]="VMM_XEN_ETC_FILES:$ETC_LOCATION/vmm_xen"
@ -179,6 +183,8 @@ INSTALL_ETC_FILES[11]="TM_DUMMY_ETC_FILES:$ETC_LOCATION/tm_dummy"
INSTALL_ETC_FILES[12]="HM_ETC_FILES:$ETC_LOCATION/hm"
INSTALL_ETC_FILES[13]="ECO_ETC_FILES:$ETC_LOCATION"
INSTALL_ETC_FILES[14]="ECO_TEMPLATE_FILES:$ETC_LOCATION/ec2query_templates"
INSTALL_ETC_FILES[15]="OCCI_ETC_FILES:$ETC_LOCATION"
INSTALL_ETC_FILES[16]="OCCI_TEMPLATE_FILES:$ETC_LOCATION/occi_templates"
#-------------------------------------------------------------------------------
# Binary files, to be installed under $BIN_LOCATION
@ -405,6 +411,32 @@ ECO_ETC_FILES="src/cloud/ec2/econe.conf"
ECO_TEMPLATE_FILES="src/cloud/ec2/templates/m1.small.erb"
#-------------------------------------------------------------------------------
# OCCI files
#-------------------------------------------------------------------------------
OCCI_LIB_FILES="src/cloud/occi/OCCI.rb \
src/cloud/occi/OCCIServer.rb \
src/cloud/occi/lib/OCCIConfiguration.rb \
src/cloud/occi/lib/ONEOCCIClient.rb \
src/cloud/occi/lib/VirtualMachineOCCI.rb \
src/cloud/occi/lib/VirtualMachinePoolOCCI.rb \
src/cloud/occi/lib/VirtualNetworkOCCI.rb \
src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb"
OCCI_BIN_FILES="src/cloud/occi/occi-server \
src/cloud/occi/commands/occi-compute \
src/cloud/occi/commands/occi-network \
src/cloud/occi/commands/occi-storage"
OCCI_ETC_FILES="src/cloud/occi/occi-server.conf"
OCCI_TEMPLATE_FILES="src/cloud/occi/templates/small.erb \
src/cloud/occi/templates/medium.erb \
src/cloud/occi/templates/large.erb"
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------

6
src/cloud/occi/OCCI.rb Normal file
View File

@ -0,0 +1,6 @@
require 'lib/VirtualMachineOCCI'
require 'lib/VirtualMachinePoolOCCI'
require 'lib/VirtualNetworkOCCI'
require 'lib/VirtualNetworkPoolOCCI'
require 'lib/OCCIConfiguration'

View File

@ -0,0 +1,442 @@
################################################
# Find out where the needed ruby libraries are
################################################
ONE_LOCATION=ENV["ONE_LOCATION"]
if !ONE_LOCATION
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
else
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
TEMPLATES_LOCATION=ONE_LOCATION+"/etc/occi_templates"
CONF_LOCATION=ONE_LOCATION+"/etc"
end
$: << RUBY_LIB_LOCATION
$: << RUBY_LIB_LOCATION+"/occiserver"
$: << RUBY_LIB_LOCATION+"/econe" # For the Repository Manager
################################################
# Required libraries
################################################
require 'rubygems'
require 'sinatra'
require 'time'
require 'pp'
require 'OpenNebula'
require 'OCCI'
include OpenNebula
CONFIG=OCCIConfiguration.new(CONF_LOCATION+'/occi-server.conf')
AUTH="#{CONFIG[:user]}:#{CONFIG[:password]}"
ONE_RM_DATABASE=CONFIG[:database]
# Load Repository Manager here to use ONE_RM_DATABASE from the configuration file
require 'repo_manager'
Image.image_dir=CONFIG[:image_dir]
INSTANCE_TYPES=Hash.new
puts "######################################"
puts " OCCI Server configuration "
puts "######################################"
puts "---------8<---------------------"
pp CONFIG
puts "------>8------------------------"
if CONFIG[:vm_type].kind_of?(Array)
# Multiple instance types
CONFIG[:vm_type].each {|type|
INSTANCE_TYPES[type['NAME']]=type
}
else
# When only one instance type is defined
INSTANCE_TYPES[CONFIG[:vm_type]['NAME']]=CONFIG[:vm_type]
end
puts "######################################"
puts " OCCI Available Instances Types "
puts "######################################"
puts "---------8<---------------------"
pp INSTANCE_TYPES
puts "------>8------------------------"
set :host, CONFIG[:server]
set :port, CONFIG[:port]
# Start repository manager
$repoman=RepoManager.new
################################################
# Client builders for ONE communication
################################################
def get_one_client
Client.new(AUTH)
end
def get_one_client_user(user_name)
user=get_user(user_name)
auth="#{user[:name]}:#{user[:password]}"
client=Client.new("dummy:dummy")
client.one_auth=auth
client
end
def get_user(name)
user=nil
user_pool=UserPool.new(get_one_client)
user_pool.info
user_pool.each{|u|
if u.name==name
user=Hash.new
user[:id]=u.id
user[:name]=u.name
user[:password]=u[:password]
end
}
user
end
###################################################
# Helpers to manage authentication & authorization
###################################################
helpers do
def protected!
response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth") and \
throw(:halt, [401, "Not authorized\n"]) and \
return unless authorized?
end
def authorized?
@auth ||= Rack::Auth::Basic::Request.new(request.env)
if !(@auth.provided? && @auth.basic? && @auth.credentials)
return false
end
user = get_user(@auth.credentials.first)
if user
if user[:password] == @auth.credentials[1]
return true
end
else
return false
end
end
end
###################################################
# Helper functions
###################################################
def submit_vm(params)
if params['occixml']
@vm_info=Crack::XML.parse(params['occixml'])
else
halt 400, "OCCI XML representation of VM not present"
end
@vm_info=@vm_info['COMPUTE']
if @vm_info['STORAGE'].class==Array
disks=@vm_info['STORAGE']
else
disks=[@vm_info['STORAGE']]
end
disks.each{|disk|
next if disk['DISK']==nil
image=$repoman.get(disk['DISK']['image'])
disk['DISK']['source']=image.path
}
@vm_info['STORAGE']=disks[0]
if @vm_info['NETWORK']['NIC'].class==Array
nics=@vm_info['NETWORK']['NIC']
else
nics=[@vm_info['NETWORK']['NIC']]
end
nics.each{|nic|
vn=VirtualNetwork.new(VirtualNetwork.build_xml(nic['network']), get_one_client)
vn.info
vn_xml=Crack::XML.parse(vn.to_xml)
nic['network_id']=nic['network']
nic['network']=vn_xml['VNET']['NAME'].strip
}
@vm_info['NETWORK']['NIC']=nics
instance_type_name=params['InstanceType']
instance_type=INSTANCE_TYPES[instance_type_name]
halt 400, "Bad instance type" if !instance_type
@vm_info[:instance_type]=instance_type_name
template=ERB.new(File.read(
TEMPLATES_LOCATION+"/#{instance_type['TEMPLATE']}"))
template_text=template.result(binding)
vm=VirtualMachineOCCI.new(
VirtualMachine.build_xml, get_one_client_user(@auth.credentials[0]))
response=vm.allocate(template_text)
if OpenNebula.is_error?(response)
status 400
response.to_str
else
vm.info
vm.to_occi
end
end
def change_state(params)
if params['occixml']
vm_info=Crack::XML.parse(params['occixml'])
else
halt 400, "OCCI XML representation of VM not present"
end
vm=VirtualMachineOCCI.new(
VirtualMachine.build_xml(params[:id]), get_one_client_user(@auth.credentials[0]))
halt 400, "State not defined in the OCCI XML, cannot change state" if !vm_info['COMPUTE']['STATE']
case vm_info['COMPUTE']['STATE']
when "stopped"
rc = vm.stop
when "suspended"
rc = vm.suspend
when "resume"
rc = vm.resume
when "cancel"
rc = vm.cancel
when "done"
rc = vm.finalize
else
halt 400, "Invalid state"
end
if OpenNebula.is_error?(rc)
status 400
response.to_str
else
status 202
response_text = "Changing state of VM " + params[:id] + " to " + vm_info['COMPUTE']['STATE']
end
end
###################################################
# Pool Resources methods
###################################################
post '/compute' do
# Auth check
protected!
submit_vm(params)
end
get '/compute' do
# Auth check
protected!
# Info retrieval
vmpool = VirtualMachinePoolOCCI.new(get_one_client)
vmpool.info
# OCCI conversion
begin
vmpool.to_occi(CONFIG[:server])
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
end
post '/network' do
# Auth check
protected!
# Info retrieval from post params
if params['occixml']
network_info=Crack::XML.parse(params['occixml'])
else
halt 400, "OCCI XML representation of Virtual Network not present in the request"
end
# Allocate the VirtualNetwork
network = VirtualNetworkOCCI.new(
VirtualNetwork.build_xml,
get_one_client_user(@auth.credentials[0]))
vntemplate = network.to_one_template(network_info['NIC'],CONFIG[:bridge])
rc = network.allocate(vntemplate)
# Return status 201 XML if correct, status 500 otherwise
if rc
halt 500, "Error creating the Virtual Network: " + rc
else
network.info
status 201
network.to_occi
end
end
get '/network' do
# Auth check
protected!
# Info retrieval
network_pool = VirtualNetworkPoolOCCI.new(get_one_client)
network_pool.info
# OCCI conversion
begin
network_pool.to_occi(CONFIG[:server])
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
end
post '/storage' do
# Auth check
protected!
# Info retrieval from post params
if params['occixml']
image_info=Crack::XML.parse(params['occixml'])
else
halt 400, "OCCI XML representation of Image not present in the request"
end
if params['file']
file=params["file"]
else
halt 400, "File not present in the request"
end
user = get_user(@auth.credentials[0])
# tmpfile where the file is stored
f_tmp=file[:tempfile]
img=$repoman.add(user[:id], f_tmp.path)
f_tmp.unlink
img.get_image_info
img.change_metadata(:name=>image_info['DISK']['NAME'])
img.change_metadata(:description=>image_info['DISK']['URL'])
xml_response = "<DISK><ID>" + img.uuid + "</ID>" +
"<NAME>" + image_info['DISK']['NAME'] + "</NAME>" +
"<SIZE>" + ((img.size/1024)/1024).to_s + "</SIZE>" +
"<URL>" + image_info['DISK']['URL'] + "<URL>" +
"</DISK>"
status 201
xml_response
end
get '/storage' do
# Auth check
protected!
# Retrieve images owned by this user
user = get_user(@auth.credentials[0])
images=Image.filter(:owner => user[:id])
image_pool = "<STORAGE>"
for image in images do
image_pool += "<DISK id=\"#{image[:uuid]}\" href=\"http://#{CONFIG[:server]}/storage/#{image[:uuid]}\">"
end
image_pool += "</STORAGE>"
image_pool
end
###################################################
# Entity Resources Methods
###################################################
get '/compute/:id' do
protected!
vm = VirtualMachineOCCI.new(VirtualMachine.build_xml(params[:id]),get_one_client_user(@auth.credentials[0]))
vm.info
begin
vm.to_occi()
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
end
delete '/compute/:id' do
protected!
vm = VirtualMachineOCCI.new(VirtualMachine.build_xml(params[:id]),get_one_client_user(@auth.credentials[0]))
vm.finalize
"The Compute resource has been successfully deleted"
end
post '/compute/:id' do
protected!
change_state(params)
end
get '/network/:id' do
protected!
vn = VirtualNetworkOCCI.new(VirtualNetwork.build_xml(params[:id]),get_one_client_user(@auth.credentials[0]))
vn.info
begin
vn.to_occi()
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
end
delete '/network/:id' do
protected!
vn = VirtualNetworkOCCI.new(VirtualNetwork.build_xml(params[:id]),get_one_client_user(@auth.credentials[0]))
vn.delete
"The Virtual Network has been successfully deleted"
end
get '/storage/:id' do
protected!
image=$repoman.get(params[:id])
image.get_image_info
if image
xml_response = "<DISK><ID>" + image.uuid + "</ID>" +
"<NAME>" + image.name + "</NAME>" +
"<SIZE>" + ((image.size/1024)/1024).to_s + "</SIZE>" +
"<URL>" + image.description + "<URL>" +
"</DISK>"
else
status 404
"Disk with id = \"" + params[:id] + "\" not found"
end
end
delete '/storage/:id' do
protected!
"Not yet implemented"
end

View File

@ -0,0 +1,220 @@
#!/usr/bin/env ruby
# == Synopsis
# occi-compute
#
# Manages compute resources
#
# == Usage
#
# occi-compute <COMMAND> [OPTIONS] [ARGUMENTS]
#
# COMMANDS
#
# create <occi xml file>
# creates a new compute resource described by the provided
# <occi xml file>
#
# list
# lists available compute resources
#
# show <compute id>
# retrieves the OCCI XML representation of the compute resource
# identified by <compute id>
#
# update <occi xml file>
# updates the representation of the compute resource represented by the
# provided <occi xml file>
#
# delete <compute id>
# deletes the compute resource idenfitied by <compute id>
#
#
# OPTIONS
#
# -h, --help:
# show help
#
# --username <id>, -U <id>:
# The username of the user
#
# --password <key>, -P <key>:
# The password of the user
#
# --url <url>, -U <url>:
# Set url as the web service url to use
#
# --debug, -D
# Enables verbosity
#
# --instance-type, -T
# Specifies the type of compute resource we want (compulsory for create)
#
# -------------------------------------------------------------------------- #
# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad #
# Complutense de Madrid (dsa-research.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. #
#--------------------------------------------------------------------------- #
ONE_LOCATION=ENV["ONE_LOCATION"]
if !ONE_LOCATION
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
else
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
TEMPLATES_LOCATION=ONE_LOCATION+"/etc/occi_templates"
CONF_LOCATION=ONE_LOCATION+"/etc"
end
$: << RUBY_LIB_LOCATION
$: << RUBY_LIB_LOCATION+"/occi"
require 'ONEOCCIClient'
require 'getoptlong'
require 'rdoc/usage'
require 'pp'
opts = GetoptLong.new(
['--help', '-h',GetoptLong::NO_ARGUMENT],
['--username', '-U',GetoptLong::REQUIRED_ARGUMENT],
['--password', '-P',GetoptLong::REQUIRED_ARGUMENT],
['--url', '-R',GetoptLong::REQUIRED_ARGUMENT],
['--instance-type','-T',GetoptLong::REQUIRED_ARGUMENT],
['--debug', '-D',GetoptLong::NO_ARGUMENT]
)
url = nil
username = nil
password = nil
auth = nil
type = nil
debug = false
begin
opts.each do |opt, arg|
case opt
when '--help'
RDoc::usage
when '--username'
username = arg
when '--password'
password = arg
when '--url'
url = arg
when '--instance-type'
type = arg
when '--debug'
debug = true
end
end
rescue Exception => e
exit -1
end
begin
occi_client = ONEOCCIClient::Client.new(url,username,password,debug)
rescue Exception => e
puts "#{$0}: #{e.message}"
exit -1
end
if !ARGV[0]
puts "#{$0}: [COMMAND] not present"
puts "#{$0}: Execute #{$0} -h for help."
exit -1
end
case ARGV[0].downcase
when 'list'
occi_client.get_vms
when 'create'
if !type
puts "#{$0}: missing compulsory instance type"
exit -1
end
vm_xml = ARGV[1]
if !vm_xml || !File.exists?(vm_xml)
puts "#{$0} create: missing OCCI-XML parameter or file not found"
exit -1
end
begin
occi_client = ONEOCCIClient::Client.new(url,username,password,debug)
rescue Exception => e
puts "#{$0} create: #{e.message}"
exit -1
end
occi_client.post_vms(type, vm_xml)
when 'show'
vm_id = ARGV[1]
if !vm_id
puts "#{$0} show: missing VM-ID parameter"
exit -1
end
begin
occi_client = ONEOCCIClient::Client.new(url,username,password,debug)
rescue Exception => e
puts "#{$0} show: #{e.message}"
exit -1
end
occi_client.get_vm(vm_id)
when 'update'
vm_xml = ARGV[1]
if !vm_xml || !File.exists?(vm_xml)
puts "#{$0} update: missing OCCI-XML parameter or file not found"
exit -1
end
begin
occi_client = ONEOCCIClient::Client.new(url,username,password,debug)
rescue Exception => e
puts "#{$0} update: #{e.message}"
exit -1
end
occi_client.put_vm(vm_xml)
when 'delete'
vm_id = ARGV[1]
if !vm_id
puts "#{$0} delete: missing VM-ID parameter"
exit -1
end
begin
occi_client = ONEOCCIClient::Client.new(url,username,password,debug)
rescue Exception => e
puts "#{$0} delete: #{e.message}"
exit -1
end
occi_client.delete_vm(vm_id)
else
puts "Command #{ARGV[0]} not valid."
exit -1
end

View File

@ -0,0 +1,173 @@
#!/usr/bin/env ruby
# == Synopsis
# occi-network
#
# Manages virtual networks
#
# == Usage
#
# occi-network <COMMAND> [OPTIONS] [ARGUMENTS]
#
# COMMANDS
#
# create <occi xml file>
# creates a new virtual network described by the provided
# <occi xml file>
#
# list
# lists available virtual networks
#
# show <network id>
# retrieves the OCCI XML representation of the virtual network
# identified by <network id>
#
# delete <network id>
# deletes the virtual network idenfitied by <network id>
#
#
# OPTIONS
#
# -h, --help:
# show help
#
# --username <id>, -U <id>:
# The username of the user
#
# --password <key>, -P <key>:
# The password of the user
#
# --url <url>, -U <url>:
# Set url as the web service url to use
#
# --debug, -D
# Enables verbosity
#
# -------------------------------------------------------------------------- #
# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad #
# Complutense de Madrid (dsa-research.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. #
#--------------------------------------------------------------------------- #
ONE_LOCATION=ENV["ONE_LOCATION"]
if !ONE_LOCATION
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
else
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
TEMPLATES_LOCATION=ONE_LOCATION+"/etc/occi_templates"
CONF_LOCATION=ONE_LOCATION+"/etc"
end
$: << RUBY_LIB_LOCATION
$: << RUBY_LIB_LOCATION+"/occi"
require 'ONEOCCIClient'
require 'getoptlong'
require 'rdoc/usage'
require 'pp'
opts = GetoptLong.new(
['--help', '-h',GetoptLong::NO_ARGUMENT],
['--username', '-U',GetoptLong::REQUIRED_ARGUMENT],
['--password', '-P',GetoptLong::REQUIRED_ARGUMENT],
['--url', '-R',GetoptLong::REQUIRED_ARGUMENT],
['--debug', '-D',GetoptLong::NO_ARGUMENT]
)
url = nil
username = nil
password = nil
auth = nil
debug = false
begin
opts.each do |opt, arg|
case opt
when '--help'
RDoc::usage
when '--username'
username = arg
when '--password'
password = arg
when '--url'
url = arg
when '--debug'
debug = true
end
end
rescue Exception => e
exit -1
end
begin
occi_client = ONEOCCIClient::Client.new(url,username,password,debug)
rescue Exception => e
puts "#{$0}: #{e.message}"
exit -1
end
if !ARGV[0]
puts "#{$0}: [COMMAND] not present"
puts "#{$0}: Execute #{$0} -h for help."
exit -1
end
case ARGV[0].downcase
when 'create'
network_xml = ARGV[1]
if !network_xml || !File.exists?(network_xml)
puts "#{$0} create: missing OCCI-XML parameter or file not found"
exit -1
end
occi_client.post_network(network_xml)
when 'list'
occi_client.get_networks
when 'show'
network_id = ARGV[1]
if !network_id
puts "#{$0} show: missing NETWORK-ID parameter or file not found"
exit -1
end
occi_client.get_network(network_id)
when 'delete'
network_id = ARGV[1]
if !network_id
puts "#{$0} delete: missing NETWORK-ID parameter"
exit -1
end
occi_client.delete_network(network_id)
else
puts "Command #{ARGV[0]} not valid."
exit -1
end

View File

@ -0,0 +1,163 @@
#!/usr/bin/env ruby
# == Synopsis
# occi-storage
#
# Manages OCCI storage resource
#
# == Usage
#
# occi-storage <COMMAND> [OPTIONS] [PARAMETERS]
#
# COMMANDS
#
# create <occi xml file>
# creates a new storage resource described by the provided
# <occi xml file>
#
# list
# lists available storage resources
#
# show <storage id>
# retrieves the OCCI XML representation of the storage resource
# identified by <storage id>
#
# update <occi xml file>
# updates the representation of the storage resource represented by the
# provided <occi xml file>
#
# delete <storage id>
# deletes the storage resource idenfitied by <storage id>
#
#
# OPTIONS
# -h, --help:
# show help
#
# --username <id>, -U <id>:
# The username of the user
#
# --password <key>, -P <key>:
# The password of the user
#
# --url <url>, -U <url>:
# Set url as the web service url to use
#
# --debug, -D
# Enables verbosity
#
# -------------------------------------------------------------------------- #
# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad #
# Complutense de Madrid (dsa-research.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. #
#--------------------------------------------------------------------------- #
ONE_LOCATION=ENV["ONE_LOCATION"]
if !ONE_LOCATION
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
else
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
TEMPLATES_LOCATION=ONE_LOCATION+"/etc/occi_templates"
CONF_LOCATION=ONE_LOCATION+"/etc"
end
$: << RUBY_LIB_LOCATION
$: << RUBY_LIB_LOCATION+"/occi"
require 'ONEOCCIClient'
require 'getoptlong'
require 'rdoc/usage'
require 'pp'
opts = GetoptLong.new(
['--help', '-h',GetoptLong::NO_ARGUMENT],
['--username', '-U',GetoptLong::REQUIRED_ARGUMENT],
['--password', '-P',GetoptLong::REQUIRED_ARGUMENT],
['--url', '-R',GetoptLong::REQUIRED_ARGUMENT],
['--debug', '-D',GetoptLong::NO_ARGUMENT]
)
url = nil
username = nil
password = nil
auth = nil
debug = false
begin
opts.each do |opt, arg|
case opt
when '--help'
RDoc::usage
when '--username'
username = arg
when '--password'
password = arg
when '--url'
url = arg
when '--debug'
debug = true
end
end
rescue Exception => e
exit -1
end
begin
occi_client = ONEOCCIClient::Client.new(url,username,password,debug)
rescue Exception => e
puts "#{$0}: #{e.message}"
exit -1
end
case ARGV[0].downcase
when 'create'
image_xml = ARGV[1]
if !image_xml || !File.exists?(image_xml)
puts "#{$0} create: missing occi xml parameter or file not found"
exit -1
end
occi_client.post_image(image_xml)
when 'list'
occi_client.get_images
when 'show'
image_id = ARGV[1]
if !image_id
puts "#{$0} show: missing storage id parameter or file not found"
exit -1
end
occi_client.get_image(image_id)
when 'delete'
puts 'Delete still not implemented'
exit -1
else
puts "Command #{ARGV[0]} not valid."
exit -1
end

View File

@ -0,0 +1,73 @@
class OCCIConfiguration
NAME_REG=/[\w\d_-]+/
VARIABLE_REG=/\s*(#{NAME_REG})\s*=\s*/
SIMPLE_VARIABLE_REG=/#{VARIABLE_REG}([^\[]+?)(#.*)?/
SINGLE_VARIABLE_REG=/^#{SIMPLE_VARIABLE_REG}$/
ARRAY_VARIABLE_REG=/^#{VARIABLE_REG}\[(.*?)\]/m
def initialize(file)
@conf=parse_conf(file)
end
def add_value(conf, key, value)
if conf[key]
if !conf[key].kind_of?(Array)
conf[key]=[conf[key]]
end
conf[key]<<value
else
conf[key]=value
end
end
def parse_conf(file)
conf_file=File.read(file)
conf=Hash.new
conf_file.scan(SINGLE_VARIABLE_REG) {|m|
key=m[0].strip.upcase
value=m[1].strip
# hack to skip multiline VM_TYPE values
next if %w{NAME TEMPLATE}.include? key.upcase
add_value(conf, key, value)
}
conf_file.scan(ARRAY_VARIABLE_REG) {|m|
master_key=m[0].strip.upcase
pieces=m[1].split(',')
vars=Hash.new
pieces.each {|p|
key, value=p.split('=')
vars[key.strip.upcase]=value.strip
}
add_value(conf, master_key, vars)
}
conf
end
def conf
@conf
end
def [](key)
@conf[key.to_s.upcase]
end
end
if $0 == __FILE__
require 'pp'
conf=OCCIConfiguration.new('occi-server.conf')
pp conf.conf
end

View File

@ -0,0 +1,303 @@
#!/usr/bin/ruby
require 'rubygems'
require 'curb'
require 'uri'
require 'OpenNebula'
require 'Crack'
module ONEOCCIClient
#####################################################################
#
#
#####################################################################
class Client
#######################################################################
#
#
#######################################################################
def initialize(endpoint_str=nil, user=nil, pass=nil, debug_flag=false)
@debug = debug_flag
# Server location
if endpoint_str
@endpoint = endpoint_str
elsif ENV["OCCI_URL"]
@endpoint = ENV["OCCI_URL"]
else
@endpoint = "http://localhost:4567"
end
# Autentication
if user && pass
@occiauth = user + ":" + Digest::SHA1.hexdigest(pass)
elsif ENV["ONE_AUTH"]
one_auth= ENV["ONE_AUTH"]
one_auth=~/(\w+):(\w+)/
user = $1
pass = $2
@occiauth = user + ":" + Digest::SHA1.hexdigest(pass)
elsif
raise "No authorization data present"
end
end
#######################################################################
# Pool Resource Request Methods
#######################################################################
#######################################################################
# Post a new VM to the VM Pool
# :instance_type
# :xmlfile
#######################################################################
def post_vms(instance_type,xmlfile)
curl=Curl::Easy.new(@endpoint+"/compute")
curl.userpwd=@occiauth
curl.verbose=true if @debug
xml=File.read(xmlfile)
begin
curl.http_post(
Curl::PostField.content('occixml', xml),
Curl::PostField.content('InstanceType', instance_type)
)
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# Retieves the pool of Virtual Machines
#######################################################################
def get_vms
curl=Curl::Easy.new(@endpoint+"/compute")
curl.userpwd=@occiauth
curl.verbose=true if @debug
begin
curl.http_get
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# Post a new Network to the VN Pool
# :xmlfile xml description of the Virtual Network
#######################################################################
def post_network(xmlfile)
curl=Curl::Easy.new(@endpoint+"/network")
curl.userpwd=@occiauth
curl.verbose=true if @debug
xml=File.read(xmlfile)
begin
curl.http_post(
Curl::PostField.content('occixml', xml)
)
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# Retieves the pool of Virtual Networks
#######################################################################
def get_networks
curl=Curl::Easy.new(@endpoint+"/network")
curl.userpwd=@occiauth
curl.verbose=true if @debug
begin
curl.http_get
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# Post a new Image to the Image Pool
# :xmlfile
#######################################################################
def post_image(xmlfile)
xml=File.read(xmlfile)
image_info=Crack::XML.parse(xml)
curl=Curl::Easy.new(@endpoint+"/storage")
curl.userpwd=@occiauth
curl.verbose=true if @debug
curl.multipart_form_post = true
file_path = image_info['DISK']['URL']
m=file_path.match(/^\w+:\/\/(.*)$/)
if m
file_path="/"+m[1]
end
begin
curl.http_post(
Curl::PostField.content('occixml', xml),
Curl::PostField.file('file', file_path)
)
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# Retieves the pool of Images owned by the user
#######################################################################
def get_images
curl=Curl::Easy.new(@endpoint+"/storage")
curl.userpwd=@occiauth
curl.verbose=true if @debug
begin
curl.http_get
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# Entity Resource Request Methods
#######################################################################
#######################################################################
# :id VM identifier
#######################################################################
def get_vm(id)
curl=Curl::Easy.new(@endpoint+"/compute/" + id.to_s)
curl.userpwd=@occiauth
curl.verbose=true if @debug
begin
curl.http_get
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# Puts a new Compute representation in order to change its state
# :xmlfile Compute OCCI xml representation
#######################################################################
def put_vm(xmlfile)
xml=File.read(xmlfile)
vm_info=Crack::XML.parse(xml)
curl=Curl::Easy.new(@endpoint+"/compute/"+vm_info['ID'])
curl.userpwd=@occiauth
curl.verbose=true if @debug
begin
curl.http_post(Curl::PostField.content('occixml', xml))
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# :id Compute identifier
#######################################################################
def delete_vm(id)
curl=Curl::Easy.new(@endpoint+"/compute/" + id.to_s)
curl.userpwd=@occiauth
curl.verbose=true if @debug
begin
curl.http_delete
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# Retrieves a Virtual Network
# :id Virtual Network identifier
#######################################################################
def get_network(id)
curl=Curl::Easy.new(@endpoint+"/network/" + id.to_s)
curl.userpwd=@occiauth
curl.verbose=true if @debug
begin
curl.http_get
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# :id VM identifier
#######################################################################
def delete_network(id)
curl=Curl::Easy.new(@endpoint+"/network/" + id.to_s)
curl.userpwd=@occiauth
curl.verbose=true if @debug
begin
curl.http_delete
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
#######################################################################
# Retieves an Image
# :image_uuid Image identifier
#######################################################################
def get_image(image_uuid)
curl=Curl::Easy.new(@endpoint+"/storage/"+image_uuid)
curl.userpwd=@occiauth
curl.verbose=true if @debug
begin
curl.http_get
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error
end
puts curl.body_str
end
end
end

View File

@ -0,0 +1,69 @@
require 'OpenNebula'
include OpenNebula
class VirtualMachineOCCI < VirtualMachine
# Creates the VMI representation of a Virtual Machine
def to_occi
occi_xml = "<COMPUTE>"
occi_xml += "<ID>" + id.to_s + "</ID>"
occi_xml += "<NAME>" + self['NAME'] + "</NAME>"
occi_xml += "<TYPE>" + self['OCCI_SIZE_TYPE'] + "</TYPE>" if self['OCCI_SIZE_TYPE']
occi_xml += "<STATE>" + state_str + "</STATE>"
# Now let's parse the template
template=self.to_hash("TEMPLATE")
template['DISK']=[template['DISK']].flatten
if template['DISK']
occi_xml += "<STORAGE>"
template['DISK'].each{|disk|
case disk['TYPE']
when "disk" then
occi_xml += "<DISK image=\"#{disk['IMAGE_ID']}\" dev=\"#{disk['DEV']}\"/>"
when "swap" then
occi_xml += "<SWAP size=\"#{disk['SIZE']}\" dev=\"#{disk['DEV']}\"/>"
when "fs" then
occi_xml += "<FS size=\"#{disk['SIZE']}\" format=\"#{disk['FORMAT']}\" dev=\"#{disk['DEV']}\"/>"
end
}
occi_xml += "</STORAGE>"
end
template['NIC']=[template['NIC']].flatten
if template['NIC']
occi_xml += "<NETWORK>"
template['NIC'].each{|nic|
occi_xml += "<NIC network=\"#{nic['VNID']}\""
if nic['IP']
occi_xml += " ip=\"#{nic['IP']}\""
end
occi_xml += "/>"
}
occi_xml += "</NETWORK>"
end
occi_xml += "</COMPUTE>"
return occi_xml
end
end
if $0 == __FILE__
t=VirtualMachineOCCI.new(VirtualMachine.build_xml(6),Client.new("tinova:opennebula"))
# t=VirtualMachineOCCI.new(VirtualMachine.build_xml,nil)
t.info
puts t.to_occi
end

View File

@ -0,0 +1,19 @@
require 'OpenNebula'
require 'Crack'
include OpenNebula
class VirtualMachinePoolOCCI < VirtualMachinePool
# Creates the OCCI representation of a Virtual Machine Pool
def to_occi(base_url)
pool_hash=Crack::XML.parse(to_xml)
occi_xml = "<COMPUTES>"
pool_hash['VM_POOL']['VM'].each{|vm|
occi_xml+='<COMPUTE id="' + vm['ID'].strip + '"' +
' href="' + base_url + '/compute/' + vm['ID'].strip + '"/>'
}
occi_xml += "</COMPUTES>"
end
end

View File

@ -0,0 +1,28 @@
require 'OpenNebula'
require 'Crack'
include OpenNebula
class VirtualNetworkOCCI < VirtualNetwork
# Creates the OCCI representation of a Virtual Network
def to_occi()
vn_hash=Crack::XML.parse(to_xml)
occi_xml = "<NIC>"
occi_xml += "<ID>" + vn_hash['VNET']['ID'].strip + "</ID>"
occi_xml += "<NAME>" + vn_hash['VNET']['NAME'].strip + "</NAME>"
occi_xml += "<ADDRESS>" + vn_hash['VNET']['TEMPLATE']['NETWORK_ADDRESS'].strip + "</ADDRESS>"
occi_xml += "<SIZE>" + vn_hash['VNET']['TEMPLATE']['NETWORK_SIZE'].strip + "</SIZE>"
occi_xml += "</NIC>"
end
def to_one_template(network_hash, bridge)
one_template = "NAME=" + network_hash['NAME'] + "\n"
one_template += "TYPE=RANGED\n"
one_template += "BRIDGE=" + bridge + "\n"
one_template += "NETWORK_ADDRESS=" + network_hash['ADDRESS'] + "\n"
one_template += "NETWORK_SIZE=" + network_hash['SIZE'] + "\n"
end
end

View File

@ -0,0 +1,19 @@
require 'OpenNebula'
require 'Crack'
include OpenNebula
class VirtualNetworkPoolOCCI < VirtualNetworkPool
# Creates the VMI representation of a Virtual Network
def to_occi(base_url)
network_pool_hash=Crack::XML.parse(to_xml)
occi_xml = "<NETWORK>"
network_pool_hash['VNET_POOL']['VNET'].each{|network|
occi_xml+='<NIC id="' + network['ID'].strip + '"' +
' href="' + base_url + '/network/' + network['ID'].strip + '"/>'
}
occi_xml += "</NETWORK>"
end
end

9
src/cloud/occi/occi-server Executable file
View File

@ -0,0 +1,9 @@
#!/bin/bash
eval `grep ^IMAGE_DIR= $ONE_LOCATION/etc/occi-server.conf `
export TMPDIR=$IMAGE_DIR/tmp
mkdir -p $TMPDIR
nohup ruby $ONE_LOCATION/lib/ruby/occi/OCCIServer.rb >> $ONE_LOCATION/var/occi-server.log &

View File

@ -0,0 +1,26 @@
# OpenNebula administrator user
USER=oneadmin
PASSWORD=<PUT HERE ONEADMIN PASS>
# OpenNebula server contact information
ONE_XMLRPC=http://localhost:2633/RPC2
# Host and port where the occi server will run
SERVER=<FQDN OF OCCI SERVER>
PORT=4567
# Configuration for the image repository
DATABASE=<ONELOCATION>/var/occi.db
IMAGE_DIR=<PATH TO EXISTING IMAGE DIRECTORY>
# Configuration for OpenNebula's Virtual Networks
BRIDGE=<NAME OF DEFAULT BRIDGE>
# Default format for FS
FS_FORMAT=ext3
# VM types allowed and its template file (inside templates directory)
VM_TYPE=[NAME=small, TEMPLATE=small.erb]
VM_TYPE=[NAME=medium, TEMPLATE=medium.erb]
VM_TYPE=[NAME=large, TEMPLATE=large.erb]

View File

@ -0,0 +1,45 @@
NAME = <%= @vm_info['NAME']%>
CPU = 8
MEMORY = 8192
OS = [ kernel = /vmlinuz,
initrd = /initrd.img,
root = sda1,
kernel_cmd = "ro xencons=tty console=tty1"]
<% @vm_info['STORAGE'].each do |key, image|
case key
when "SWAP"
%>
DISK = [ type = "swap",
size=<%= image['size']%>,
dev=<%= image['dev']%> ]
<%
when "DISK"
%>
DISK = [ type = "disk",
dev=<%= image['dev']%>,
source=<%= image['source']%>,
image_id=<%= image['image']%> ]
<%
when "FS"
%>
DISK = [ type = "fs",
dev=<%= image['dev']%>,
size=<%= image['size']%>,
format=<%= CONFIG[:fs_format]||"ext3"%> ]
<% end %>
<% end %>
<% @vm_info['NETWORK']['NIC'].each do |nic| %>
NIC = [
<% if nic['ip'] %>
IP=<%= nic['ip'] %>,
<% end %>
NETWORK=<%= nic['network']%>,
NETWORK_ID=<%= nic['network_id'] %>
]
<% end %>
OCCI_SIZE_TYPE = <%= @vm_info[:instance_type ]%>

View File

@ -0,0 +1,45 @@
NAME = <%= @vm_info['NAME']%>
CPU = 4
MEMORY = 4096
OS = [ kernel = /vmlinuz,
initrd = /initrd.img,
root = sda1,
kernel_cmd = "ro xencons=tty console=tty1"]
<% @vm_info['STORAGE'].each do |key, image|
case key
when "SWAP"
%>
DISK = [ type = "swap",
size=<%= image['size']%>,
dev=<%= image['dev']%> ]
<%
when "DISK"
%>
DISK = [ type = "disk",
dev=<%= image['dev']%>,
source=<%= image['source']%>,
image_id=<%= image['image']%> ]
<%
when "FS"
%>
DISK = [ type = "fs",
dev=<%= image['dev']%>,
size=<%= image['size']%>,
format=<%= CONFIG[:fs_format]||"ext3"%> ]
<% end %>
<% end %>
<% @vm_info['NETWORK']['NIC'].each do |nic| %>
NIC = [
<% if nic['ip'] %>
IP=<%= nic['ip'] %>,
<% end %>
NETWORK=<%= nic['network']%>,
NETWORK_ID=<%= nic['network_id'] %>
]
<% end %>
OCCI_SIZE_TYPE = <%= @vm_info[:instance_type ]%>

View File

@ -0,0 +1,45 @@
NAME = <%= @vm_info['NAME']%>
CPU = 1
MEMORY = 1024
OS = [ kernel = /vmlinuz,
initrd = /initrd.img,
root = sda1,
kernel_cmd = "ro xencons=tty console=tty1"]
<% @vm_info['STORAGE'].each do |key, image|
case key
when "SWAP"
%>
DISK = [ type = "swap",
size=<%= image['size']%>,
dev=<%= image['dev']%> ]
<%
when "DISK"
%>
DISK = [ type = "disk",
dev=<%= image['dev']%>,
source=<%= image['source']%>,
image_id=<%= image['image']%> ]
<%
when "FS"
%>
DISK = [ type = "fs",
dev=<%= image['dev']%>,
size=<%= image['size']%>,
format=<%= CONFIG[:fs_format]||"ext3"%> ]
<% end %>
<% end %>
<% @vm_info['NETWORK']['NIC'].each do |nic| %>
NIC = [
<% if nic['ip'] %>
IP=<%= nic['ip'] %>,
<% end %>
NETWORK=<%= nic['network']%>,
NETWORK_ID=<%= nic['network_id'] %>
]
<% end %>
OCCI_SIZE_TYPE = <%= @vm_info[:instance_type ]%>