1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-27 14:03:40 +03:00

Merge branch 'master' into feature-1112

This commit is contained in:
Carlos Martín 2012-02-28 12:33:05 +01:00
commit 4d5ea6f8a2
69 changed files with 1327 additions and 754 deletions

View File

@ -313,12 +313,12 @@ public:
static string version()
{
return "OpenNebula 3.2.0";
return "OpenNebula 3.3.0";
};
static string db_version()
{
return "3.2.0";
return "3.3.0";
}
void start();

View File

@ -268,6 +268,7 @@ SUNSTONE_DIRS="$SUNSTONE_LOCATION/models \
$SUNSTONE_LOCATION/public/vendor/jQuery \
$SUNSTONE_LOCATION/public/vendor/jGrowl \
$SUNSTONE_LOCATION/public/vendor/flot \
$SUNSTONE_LOCATION/public/vendor/fileuploader \
$SUNSTONE_LOCATION/public/images \
$SUNSTONE_LOCATION/templates \
$SUNSTONE_LOCATION/views"
@ -460,6 +461,7 @@ INSTALL_SUNSTONE_FILES=(
SUNSTONE_PUBLIC_VENDOR_JQUERYUIIMAGES:$SUNSTONE_LOCATION/public/vendor/jQueryUI/images
SUNSTONE_PUBLIC_VENDOR_JQUERYLAYOUT:$SUNSTONE_LOCATION/public/vendor/jQueryLayout
SUNSTONE_PUBLIC_VENDOR_FLOT:$SUNSTONE_LOCATION/public/vendor/flot
SUNSTONE_PUBLIC_VENDOR_FILEUPLOADER:$SUNSTONE_LOCATION/public/vendor/fileuploader
SUNSTONE_PUBLIC_IMAGES_FILES:$SUNSTONE_LOCATION/public/images
SUNSTONE_PUBLIC_LOCALE_EN_US:$SUNSTONE_LOCATION/public/locale/en_US
SUNSTONE_PUBLIC_LOCALE_RU:$SUNSTONE_LOCATION/public/locale/ru
@ -834,6 +836,7 @@ ONEDB_MIGRATOR_FILES="src/onedb/2.0_to_2.9.80.rb \
src/onedb/3.1.0_to_3.1.80.rb \
src/onedb/3.1.80_to_3.2.0.rb \
src/onedb/3.2.0_to_3.2.1.rb \
src/onedb/3.2.1_to_3.3.0.rb \
src/onedb/onedb.rb \
src/onedb/onedb_backend.rb"
@ -1032,7 +1035,8 @@ OCCI_LIB_FILES="src/cloud/occi/lib/OCCIServer.rb \
src/cloud/occi/lib/UserOCCI.rb \
src/cloud/occi/lib/UserPoolOCCI.rb \
src/cloud/occi/lib/ImageOCCI.rb \
src/cloud/occi/lib/ImagePoolOCCI.rb"
src/cloud/occi/lib/ImagePoolOCCI.rb \
src/sunstone/OpenNebulaVNC.rb"
OCCI_LIB_CLIENT_FILES="src/cloud/occi/lib/OCCIClient.rb"
@ -1102,7 +1106,8 @@ ETC_CLIENT_FILES="src/cli/etc/group.default"
#-----------------------------------------------------------------------------
SUNSTONE_FILES="src/sunstone/config.ru \
src/sunstone/sunstone-server.rb"
src/sunstone/sunstone-server.rb \
src/sunstone/OpenNebulaVNC.rb"
SUNSTONE_BIN_FILES="src/sunstone/bin/sunstone-server"

View File

@ -7,19 +7,12 @@ DEFAULT=%w{optional sunstone quota cloud ozones_server acct auth_ldap}
if defined?(RUBY_VERSION) && RUBY_VERSION>="1.8.7"
SQLITE='sqlite3'
# xmlparser gem is not compatible with ruby 1.9
OPTIONAL=%w{nokogiri}
if RUBY_VERSION=='1.8.7'
OPTIONAL << 'xmlparser'
end
else
SQLITE='sqlite3-ruby --version 1.2.0'
OPTIONAL=%w{nokogiri xmlparser}
end
GROUPS={
:optional => OPTIONAL,
:optional => ['nokogiri'],
:quota => [SQLITE, 'sequel'],
:sunstone => ['json', 'rack', 'sinatra', 'thin', 'sequel', SQLITE],
:cloud => %w{amazon-ec2 rack sinatra thin uuidtools curb json},

View File

@ -1,40 +1,56 @@
#!/bin/bash
NOVNC_TMP=/tmp/one/novnc-$(date "+%Y%m%d%H%M%S")
PROXY_PATH=noVNC/utils/websockify
if [ -z "$ONE_LOCATION" ]; then
ONE_SHARE=/usr/share/one
ONE_PUBLIC_SUNSTONE=/usr/lib/one/sunstone/public
SUNSTONE_CONF=/etc/one/sunstone-server.conf
ONE_PUBLIC_SELFSERVICE=/usr/lib/one/ruby/cloud/occi/ui/public
SELFSERVICE_CONF=/etc/one/occi-server.conf
else
ONE_SHARE=$ONE_LOCATION/share
ONE_PUBLIC_SUNSTONE=$ONE_LOCATION/lib/sunstone/public
SUNSTONE_CONF=$ONE_LOCATION/etc/sunstone-server.conf
ONE_PUBLIC_SELFSERVICE=$ONE_LOCATION/lib/ruby/cloud/occi/ui/public
SELFSERVICE_CONF=$ONE_LOCATION/etc/occi-server.conf
fi
echo "Downloading noVNC latest version..."
mkdir -p $NOVNC_TMP
wget -P $NOVNC_TMP --no-check-certificate http://github.com/kanaka/noVNC/tarball/master
cd $NOVNC_TMP
curl -O -# -L http://github.com/kanaka/noVNC/tarball/master
if [ $? -ne 0 ]; then
echo "Error downloading noVNC"
echo "\nError downloading noVNC"
exit 1
fi
echo "Extracting files to temporary folder..."
tar=`ls -rt $NOVNC_TMP|tail -n1`
tar -C $ONE_SHARE -mxvzf $NOVNC_TMP/$tar
tar -C $ONE_SHARE -mxzf $NOVNC_TMP/$tar
if [ $? -ne 0 ]; then
echo "Error untaring noVNC"
exit 1
fi
echo "Moving files to OpenNebula $ONE_SHARE folder..."
rm -rf $ONE_SHARE/noVNC
dir=`ls -rt $ONE_SHARE|tail -n1`
mv $ONE_SHARE/$dir $ONE_SHARE/noVNC
echo "Installing Sunstone client libraries in $ONE_PUBLIC_SUNSTONE..."
mkdir -p $ONE_PUBLIC_SUNSTONE/vendor/noVNC
mv $ONE_SHARE/noVNC/include/ $ONE_PUBLIC_SUNSTONE/vendor/noVNC/
cp -r $ONE_SHARE/noVNC/include/ $ONE_PUBLIC_SUNSTONE/vendor/noVNC/
sed -i.bck "s%^\(:novnc_path: \).*$%\1$ONE_SHARE/noVNC%" $SUNSTONE_CONF
echo "Installing SelfService client libraries in $ONE_PUBLIC_SELFSERVICE..."
mkdir -p $ONE_PUBLIC_SELFSERVICE/vendor/noVNC
cp -r $ONE_SHARE/noVNC/include/ $ONE_PUBLIC_SELFSERVICE/vendor/noVNC/
#Update file permissions
chmod +x $ONE_SHARE/noVNC/utils/launch.sh
echo "Backing up and updating $SUNSTONE_CONF with new VNC proxy path..."
sed -i.bck "s%^\(:vnc_proxy_path:\).*$%\1 $ONE_SHARE/$PROXY_PATH%" $SUNSTONE_CONF
echo "Backing up and updating $SELFSERVICE_CONF with new VNC proxy path..."
sed -i.bck "s%^\(:vnc_proxy_path:\).*$%\1 $ONE_SHARE/$PROXY_PATH%" $SELFSERVICE_CONF
echo "Installation successful"

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH OPENNEBULA "1" "January 2012" "OpenNebula 3.2.0" "User Commands"
.TH OPENNEBULA "1" "February 2012" "OpenNebula 3.3.0" "User Commands"
.SH NAME
OpenNebula \- OpenNebula econe-describe-images
.SH SYNOPSIS

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH OPENNEBULA "1" "January 2012" "OpenNebula 3.2.0" "User Commands"
.TH OPENNEBULA "1" "February 2012" "OpenNebula 3.3.0" "User Commands"
.SH NAME
OpenNebula \- OpenNebula econe-describe-instances
.SH SYNOPSIS

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH OPENNEBULA "1" "January 2012" "OpenNebula 3.2.0" "User Commands"
.TH OPENNEBULA "1" "February 2012" "OpenNebula 3.3.0" "User Commands"
.SH NAME
OpenNebula \- OpenNebula econe-register
.SH SYNOPSIS

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH OPENNEBULA "1" "January 2012" "OpenNebula 3.2.0" "User Commands"
.TH OPENNEBULA "1" "February 2012" "OpenNebula 3.3.0" "User Commands"
.SH NAME
OpenNebula \- OpenNebula econe-run-instances
.SH SYNOPSIS

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH OPENNEBULA "1" "January 2012" "OpenNebula 3.2.0" "User Commands"
.TH OPENNEBULA "1" "February 2012" "OpenNebula 3.3.0" "User Commands"
.SH NAME
OpenNebula \- OpenNebula econe-terminate-instances
.SH SYNOPSIS

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH OPENNEBULA "1" "September 2011" "OpenNebula 3.2.0" "User Commands"
.TH OPENNEBULA "1" "September 2011" "OpenNebula 3.3.0" "User Commands"
.SH NAME
OpenNebula \- OpenNebula econe-upload
.SH SYNOPSIS

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH OPENNEBULA "1" "January 2012" "OpenNebula 3.2.0" "User Commands"
.TH OPENNEBULA "1" "February 2012" "OpenNebula 3.3.0" "User Commands"
.SH NAME
OpenNebula \- OpenNebula occi-compute
.SH SYNOPSIS

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH OPENNEBULA "1" "January 2012" "OpenNebula 3.2.0" "User Commands"
.TH OPENNEBULA "1" "February 2012" "OpenNebula 3.3.0" "User Commands"
.SH NAME
OpenNebula \- OpenNebula occi-network
.SH SYNOPSIS

View File

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH OPENNEBULA "1" "January 2012" "OpenNebula 3.2.0" "User Commands"
.TH OPENNEBULA "1" "February 2012" "OpenNebula 3.3.0" "User Commands"
.SH NAME
OpenNebula \- OpenNebula occi-storage
.SH SYNOPSIS

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEACL" "1" "January 2012" "" "oneacl(1) -- manages OpenNebula ACLs"
.TH "ONEACL" "1" "February 2012" "" "oneacl(1) -- manages OpenNebula ACLs"
.
.SH "NAME"
\fBoneacl\fR
@ -128,7 +128,7 @@ Comma\-separated list of OpenNebula ACL names or ids
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEDB" "1" "January 2012" "" "onedb(1) -- OpenNebula database migration tool"
.TH "ONEDB" "1" "February 2012" "" "onedb(1) -- OpenNebula database migration tool"
.
.SH "NAME"
\fBonedb\fR

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEGROUP" "1" "January 2012" "" "onegroup(1) -- manages OpenNebula groups"
.TH "ONEGROUP" "1" "February 2012" "" "onegroup(1) -- manages OpenNebula groups"
.
.SH "NAME"
\fBonegroup\fR
@ -160,7 +160,7 @@ Comma\-separated list of OpenNebula GROUP names or ids
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEHOST" "1" "January 2012" "" "onehost(1) -- manages OpenNebula hosts"
.TH "ONEHOST" "1" "February 2012" "" "onehost(1) -- manages OpenNebula hosts"
.
.SH "NAME"
\fBonehost\fR
@ -234,7 +234,7 @@ Comma\-separated list of OpenNebula HOST names or ids
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEIMAGE" "1" "January 2012" "" "oneimage(1) -- manages OpenNebula images"
.TH "ONEIMAGE" "1" "February 2012" "" "oneimage(1) -- manages OpenNebula images"
.
.SH "NAME"
\fBoneimage\fR
@ -381,7 +381,7 @@ user IMAGE of the user identified by the username
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONETEMPLATE" "1" "January 2012" "" "onetemplate(1) -- manages OpenNebula templates"
.TH "ONETEMPLATE" "1" "February 2012" "" "onetemplate(1) -- manages OpenNebula templates"
.
.SH "NAME"
\fBonetemplate\fR
@ -13,7 +13,10 @@
.
.nf
\-n, \-\-name vm_name Name of the new Virtual Machine
\-n, \-\-name vm_name Name of the new Virtual Machine\. When instantiating
multiple VMs you can use the"%i" wildcard to produce
different names such as vm\-0, vm\-1\.\.\.
\-m, \-\-multiple x Instance multiple VMs
\-l, \-\-list x,y,z Selects columns to display with list command
\-d, \-\-delay x Sets the delay in seconds for top command
@ -327,7 +330,7 @@ user VMTEMPLATE of the user identified by the username
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEUSER" "1" "January 2012" "" "oneuser(1) -- manages OpenNebula users"
.TH "ONEUSER" "1" "February 2012" "" "oneuser(1) -- manages OpenNebula users"
.
.SH "NAME"
\fBoneuser\fR
@ -305,7 +305,7 @@ User password
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEVDC" "1" "January 2012" "" "onevdc(1) -- manages OpenNebula Virtual DataCenters"
.TH "ONEVDC" "1" "February 2012" "" "onevdc(1) -- manages OpenNebula Virtual DataCenters"
.
.SH "NAME"
\fBonevdc\fR
@ -171,7 +171,7 @@ VDC ID
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEVM" "1" "January 2012" "" "onevm(1) -- manages OpenNebula virtual machines"
.TH "ONEVM" "1" "February 2012" "" "onevm(1) -- manages OpenNebula virtual machines"
.
.SH "NAME"
\fBonevm\fR
@ -526,7 +526,7 @@ user VM of the user identified by the username
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEVNET" "1" "January 2012" "" "onevnet(1) -- manages OpenNebula networks"
.TH "ONEVNET" "1" "February 2012" "" "onevnet(1) -- manages OpenNebula networks"
.
.SH "NAME"
\fBonevnet\fR
@ -351,7 +351,7 @@ user VNET of the user identified by the username
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "ONEZONE" "1" "January 2012" "" "onezone(1) -- manages OpenNebula zones"
.TH "ONEZONE" "1" "February 2012" "" "onezone(1) -- manages OpenNebula zones"
.
.SH "NAME"
\fBonezone\fR
@ -43,7 +43,7 @@ show \fIzoneid\fR [\fIresource\fR]
.nf
Show information of a particular Zone
Available resources: host, vm, image, vn, template, user
Available resources: host, vm, image, vnet, vmtemplate, user
Examples:
onezone show 4
onezone show 4 host
@ -144,7 +144,7 @@ Zone ID
.IP "" 0
.
.SH "LICENSE"
OpenNebula 3\.2\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
OpenNebula 3\.3\.0 Copyright 2002\-2012, OpenNebula Project Leads (OpenNebula\.org)
.
.P
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

View File

@ -22,8 +22,8 @@
# a given metric.
#-------------------------------------------------------------------------------
:defaults:
:cpu:
:memory:
:num_vms:
:storage:
:CPU:
:MEMORY:
:NUM_VMS:
:STORAGE:

View File

@ -21,7 +21,7 @@ include OpenNebula
module OpenNebulaHelper
ONE_VERSION=<<-EOT
OpenNebula 3.2.0
OpenNebula 3.3.0
Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org)
Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -365,6 +365,15 @@ EOT
end
end
def OpenNebulaHelper.period_to_str(time)
seconds=time.to_i
minutes, seconds=seconds.divmod(60)
hours, minutes=minutes.divmod(60)
days, hours=hours.divmod(24)
"%4dd %02d:%02d:%02d" % [days, hours, minutes, seconds]
end
BinarySufix = ["K", "M", "G", "T" ]
def OpenNebulaHelper.unit_to_str(value, options, unit="K")

View File

@ -92,14 +92,10 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
end
column :TIME, "Time since the VM was submitted", :size=>11 do |d|
stime = Time.at(d["STIME"].to_i)
etime = d["ETIME"]=="0" ? Time.now : Time.at(d["ETIME"].to_i)
dtime = Time.at(etime-stime).getgm
"%02d %02d:%02d:%02d" % [
dtime.yday-1,
dtime.hour,
dtime.min,
dtime.sec]
stime = d["STIME"].to_i
etime = d["ETIME"]=="0" ? Time.now.to_i : d["ETIME"].to_i
dtime = etime-stime
OpenNebulaHelper.period_to_str(dtime)
end
default :ID, :USER, :GROUP, :NAME, :STAT, :CPU, :MEM, :HOSTNAME,
@ -201,24 +197,21 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
end
column :TIME, "Total time in this state", :size=>11 do |d|
stime = Time.at(d["STIME"].to_i)
etime = d["ETIME"]=="0" ? Time.now : Time.at(d["ETIME"].to_i)
dtime = Time.at(etime-stime).getgm
"%02d %02d:%02d:%02d" % [dtime.yday-1, dtime.hour,
dtime.min, dtime.sec]
stime = d["STIME"].to_i
etime = d["ETIME"]=="0" ? Time.now.to_i : d["ETIME"].to_i
dtime = etime-stime
OpenNebulaHelper.period_to_str(dtime)
end
column :PTIME, "Prolog time for this state", :size=>11 do |d|
stime = Time.at(d["PSTIME"].to_i)
stime = d["PSTIME"].to_i
if d["PSTIME"]=="0"
etime=Time.at(0)
etime=0
else
etime = d["PETIME"]=="0" ? Time.now :
Time.at(d["PETIME"].to_i)
etime = d["PETIME"]=="0" ? Time.now.to_i: d["PETIME"].to_i
end
dtime = Time.at(etime-stime).getgm
"%02d %02d:%02d:%02d" % [dtime.yday-1, dtime.hour,
dtime.min, dtime.sec]
dtime = etime-stime
OpenNebulaHelper.period_to_str(dtime)
end
default :SEQ, :HOSTNAME, :REASON, :START, :TIME, :PTIME

View File

@ -66,18 +66,18 @@ class AcctHelper
column :NETRX, "Group of the User", :right, :size=>10 do |d|
OpenNebulaHelper.unit_to_str(
d[:network][:net_rx]/1024.0,
d[:network][:net_rx].to_i/1024.0,
{})
end
column :NETTX, "Group of the User", :right, :size=>10 do |d|
OpenNebulaHelper.unit_to_str(
d[:network][:net_tx]/1024.0,
d[:network][:net_tx].to_i/1024.0,
{})
end
column :TIME, "Group of the User", :right, :size=>15 do |d|
OpenNebulaHelper.time_to_str(d[:time])
OpenNebulaHelper.period_to_str(d[:time])
end
default :VMID, :MEMORY, :CPU, :NETRX, :NETTX, :TIME

View File

@ -110,7 +110,8 @@ cmd=CommandParser::CmdParser.new(ARGV) do
number = options[:multiple] || 1
number.times do |i|
exit_code=helper.perform_action(args[0],options,"instantiated") do |t|
name = options[:vm_name].gsub("%i",i.to_s)
name = options[:vm_name]
name = name.gsub("%i",i.to_s) if name
res = t.instantiate(name)
if !OpenNebula.is_error?(res)

View File

@ -61,7 +61,7 @@ module CloudClient
# #########################################################################
def self.get_one_auth
if ENV["ONE_AUTH"] and !ENV["ONE_AUTH"].empty? and
File.file?(ENV["ONE_AUTH"])
File.file?(ENV["ONE_AUTH"])
one_auth=File.read(ENV["ONE_AUTH"]).strip.split(':')
elsif File.file?(DEFAULT_AUTH_FILE)
one_auth=File.read(DEFAULT_AUTH_FILE).strip.split(':')
@ -91,24 +91,30 @@ module CloudClient
end
begin
http.start do |connection|
res = http.start do |connection|
block.call(connection)
end
rescue Errno::ECONNREFUSED => e
str = "Error connecting to server (#{e.to_s}).\n"
str << "Server: #{url.host}:#{url.port}"
return CloudClient::Error.new(str)
return CloudClient::Error.new(str,"503")
rescue Errno::ETIMEDOUT => e
str = "Error timeout connecting to server (#{e.to_s}).\n"
str << "Server: #{url.host}:#{url.port}"
return CloudClient::Error.new(str)
return CloudClient::Error.new(str,"504")
rescue Timeout::Error => e
str = "Error timeout while connected to server (#{e.to_s}).\n"
str << "Server: #{url.host}:#{url.port}"
return CloudClient::Error.new(str)
return CloudClient::Error.new(str,"504")
end
if res.is_a?(Net::HTTPSuccess)
res
else
CloudClient::Error.new(res.body, res.code)
end
end
@ -118,10 +124,12 @@ module CloudClient
# #########################################################################
class Error
attr_reader :message
attr_reader :code
# +message+ a description of the error
def initialize(message=nil)
def initialize(message=nil, code="500")
@message=message
@code=code
end
def to_s()
@ -140,7 +148,7 @@ end
# Command line help functions
module CloudCLI
def print_xml(xml_text)
def print_xml(xml_text)
begin
doc = REXML::Document.new(xml_text)
rescue REXML::ParseException => e
@ -173,7 +181,7 @@ module CloudCLI
def version_text
version=<<EOT
OpenNebula 3.2.0
OpenNebula 3.3.0
Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org)
Licensed under the Apache License, Version 2.0 (the "License"); you may

View File

@ -70,6 +70,7 @@ module EC2QueryClient
end
@uri = URI.parse(endpoint)
path = @uri.path.empty? ? '/' : @uri.path
@ec2_connection = AWS::EC2::Base.new(
:access_key_id => @access_key_id,
@ -77,7 +78,7 @@ module EC2QueryClient
:server => @uri.host,
:port => @uri.port,
:use_ssl => @uri.scheme == 'https',
:path => @uri.path)
:path => path)
end

View File

@ -54,8 +54,8 @@ class EC2QueryServer < CloudServer
'save' => :pending,
'epil' => :shutdown,
'shut' => :shutdown,
'clea' => :shutdown,
'fail' => :terminated,
'dele' => :terminated,
'unkn' => :terminated
}
@ -211,7 +211,8 @@ class EC2QueryServer < CloudServer
# Helper functions
###########################################################################
def render_state(vm)
ec2_state = EC2_STATES[ONE_STATES[vm.status]]
one_state = ONE_STATES[vm.status]
ec2_state = EC2_STATES[one_state||:pending]
return "<code>#{ec2_state[:code]}</code>
<name>#{ec2_state[:name]}</name>"

View File

@ -12,7 +12,6 @@
</groupSet>
<instancesSet>
<% vmpool.each do |vm| %>
<% vm.info %>
<item>
<instanceId>i-<%= vm.id %></instanceId>
<imageId><%= vm['TEMPLATE/IMAGE_ID'] %></imageId>

View File

@ -52,5 +52,26 @@
:cpu: 8
:memory: 8192
# Default language setting for Self-Service UI
#############################################################
# OCCI UI Settings (SelfService)
#############################################################
# Default language setting
:lang: en_US
# VNC Configuration
# vnc_enable: yes | no. Allow users to launch vnc sessions.
# base_port: base_port + vnc_port of the VM is the port where the
# proxy will listen for VNC session connections to that VM.
# vnc_proxy_path: path to the websockets proxy (set by install_novnc.sh)
# support_wss: no | yes | only. If yes or only provide path to cert and key.
# "yes" means the proxy will accept both ws and wss connections.
# vnc_proxy_cert: Certificate to encrypt wss connections.
# vnc_proxy_key: Key for wss connections. Only necessary if not included in cert.
:vnc_enable: no
:vnc_proxy_base_port: 33876
:vnc_proxy_path:
:vnc_proxy_support_wss: no
:vnc_proxy_cert:
:vnc_proxy_key:

View File

@ -23,6 +23,8 @@ class ImageOCCI < Image
<STORAGE href="<%= base_url %>/storage/<%= self.id.to_s %>">
<ID><%= self.id.to_s %></ID>
<NAME><%= self.name %></NAME>
<USER href="<%= base_url %>/user/<%= self['UID'] %>" name="<%= self['UNAME'] %>"/>
<GROUP><%= self['GNAME'] %></GROUP>
<STATE><%= self.state_str %></STATE>
<% if self['TYPE'] != nil %>
<TYPE><%= self.type_str %></TYPE>
@ -82,7 +84,7 @@ class ImageOCCI < Image
end
# Creates the OCCI representation of an Image
def to_occi(base_url)
def to_occi(base_url, verbose=false)
begin
occi_im = ERB.new(OCCI_IMAGE)
occi_im_text = occi_im.result(binding)

View File

@ -14,22 +14,23 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
require 'OpenNebula'
include OpenNebula
require 'ImageOCCI'
class ImagePoolOCCI < ImagePool
OCCI_IMAGE_POOL = %q{
<STORAGE_COLLECTION>
<% self.each{ |im| %>
<% if verbose %>
<%= im.to_occi(base_url) %>
<% else %>
<STORAGE href="<%= base_url %>/storage/<%= im.id.to_s %>" name="<%= im.name %>"/>
<% end %>
<% } %>
</STORAGE_COLLECTION>
}
# Creates the OCCI representation of a Virtual Machine Pool
def to_occi(base_url)
def to_occi(base_url, verbose=false)
begin
occi = ERB.new(OCCI_IMAGE_POOL)
occi_text = occi.result(binding)
@ -40,5 +41,9 @@ class ImagePoolOCCI < ImagePool
return occi_text.gsub(/\n\s*/,'')
end
def factory(element_xml)
ImageOCCI.new(element_xml,@client)
end
end

View File

@ -30,11 +30,13 @@ module OCCIClient
#####################################################################
class Client
attr_accessor :endpoint
######################################################################
# Initialize client library
######################################################################
def initialize(endpoint_str=nil, user=nil, pass=nil,
timeout=nil, debug_flag=true)
timeout=nil, debug_flag=true)
@debug = debug_flag
@timeout = timeout
@ -65,50 +67,30 @@ module OCCIClient
# Pool Resource Request Methods #
#################################
def get_root
get('/')
end
######################################################################
# Retieves the available Instance types
######################################################################
def get_instance_types
get('/instance_type')
end
######################################################################
# Post a new VM to the VM Pool
# :instance_type
# :xmlfile
######################################################################
def post_vms(xmlfile)
xml=File.read(xmlfile)
url = URI.parse(@endpoint+"/compute")
req = Net::HTTP::Post.new(url.path)
req.body=xml
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) do |http|
http.request(req)
end
if CloudClient::is_error?(res)
return res
else
return res.body
end
post('/compute', xmlfile)
end
######################################################################
# Retieves the pool of Virtual Machines
######################################################################
def get_vms
url = URI.parse(@endpoint+"/compute")
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
get('/compute')
end
######################################################################
@ -116,44 +98,14 @@ module OCCIClient
# :xmlfile xml description of the Virtual Network
######################################################################
def post_network(xmlfile)
xml=File.read(xmlfile)
url = URI.parse(@endpoint+"/network")
req = Net::HTTP::Post.new(url.path)
req.body=xml
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) do |http|
http.request(req)
end
if CloudClient::is_error?(res)
return res
else
return res.body
end
post('/network', xmlfile)
end
######################################################################
# Retieves the pool of Virtual Networks
######################################################################
def get_networks
url = URI.parse(@endpoint+"/network")
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
get('/network')
end
######################################################################
@ -251,22 +203,10 @@ module OCCIClient
# Retieves the pool of Images owned by the user
######################################################################
def get_images
url = URI.parse(@endpoint+"/storage")
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
get('/storage')
end
####################################
# Entity Resource Request Methods #
####################################
@ -275,20 +215,7 @@ module OCCIClient
# :id VM identifier
######################################################################
def get_vm(id)
url = URI.parse(@endpoint+"/compute/" + id.to_s)
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
get('/compute/'+id.to_s)
end
######################################################################
@ -296,57 +223,14 @@ module OCCIClient
# :xmlfile Compute OCCI xml representation
######################################################################
def put_vm(xmlfile)
xml = File.read(xmlfile)
begin
vm_info = REXML::Document.new(xml).root
rescue Exception => e
error = CloudClient::Error.new(e.message)
return error
end
if vm_info.elements['ID'] == nil
return CloudClient::Error.new("Can not find COMPUTE_ID")
end
vm_id = vm_info.elements['ID'].text
url = URI.parse(@endpoint+'/compute/' + vm_id)
req = Net::HTTP::Put.new(url.path)
req.body = xml
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) do |http|
http.request(req)
end
if CloudClient::is_error?(res)
return res
else
return res.body
end
put('/compute/', xmlfile)
end
####################################################################
# :id Compute identifier
####################################################################
def delete_vm(id)
url = URI.parse(@endpoint+"/compute/" + id.to_s)
req = Net::HTTP::Delete.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
delete('/compute/'+id.to_s)
end
######################################################################
@ -354,20 +238,7 @@ module OCCIClient
# :id Virtual Network identifier
######################################################################
def get_network(id)
url = URI.parse(@endpoint+"/network/" + id.to_s)
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
get('/network/'+id.to_s)
end
######################################################################
@ -375,78 +246,22 @@ module OCCIClient
# :xmlfile Network OCCI xml representation
######################################################################
def put_network(xmlfile)
xml = File.read(xmlfile)
begin
vnet_info = REXML::Document.new(xml).root
rescue Exception => e
error = CloudClient::Error.new(e.message)
return error
end
if vnet_info.elements['ID'] == nil
return CloudClient::Error.new("Can not find NETWORK_ID")
end
vnet_id = vnet_info.elements['ID'].text
url = URI.parse(@endpoint+'/network/' + vnet_id)
req = Net::HTTP::Put.new(url.path)
req.body = xml
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) do |http|
http.request(req)
end
if CloudClient::is_error?(res)
return res
else
return res.body
end
put('/network/', xmlfile)
end
######################################################################
# :id VM identifier
######################################################################
def delete_network(id)
url = URI.parse(@endpoint+"/network/" + id.to_s)
req = Net::HTTP::Delete.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
delete('/network/'+id.to_s)
end
#######################################################################
#######################################################################
# Retieves an Image
# :image_uuid Image identifier
######################################################################
def get_image(image_uuid)
url = URI.parse(@endpoint+"/storage/"+image_uuid)
req = Net::HTTP::Get.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
def get_image(id)
get('/storage/'+id.to_s)
end
######################################################################
@ -454,26 +269,67 @@ module OCCIClient
# :xmlfile Storage OCCI xml representation
######################################################################
def put_image(xmlfile)
xml = File.read(xmlfile)
put('/storage/', xmlfile)
end
######################################################################
# :id VM identifier
######################################################################
def delete_image(id)
delete('/storage/'+id.to_s)
end
private
def get(path)
url = URI.parse(@endpoint+path)
req = Net::HTTP::Get.new(url.path)
do_request(url, req)
end
def post(path, xmlfile)
url = URI.parse(@endpoint+path)
req = Net::HTTP::Post.new(url.path)
req.body=File.read(xmlfile)
do_request(url, req)
end
def delete(path, xmlfile)
url = URI.parse(@endpoint+path)
req = Net::HTTP::Delete.new(url.path)
do_request(url, req)
end
def put(path, xmlfile)
xml = File.read(xmlfile)
# Get ID from XML
begin
image_info = REXML::Document.new(xml).root
info = REXML::Document.new(xml).root
rescue Exception => e
error = OpenNebula::Error.new(e.message)
error = CloudClient::Error.new(e.message)
return error
end
if image_info.elements['ID'] == nil
return CloudClient::Error.new("Can not find STORAGE_ID")
if info.elements['ID'] == nil
return CloudClient::Error.new("Can not find RESOURCE ID")
end
image_id = image_info.elements['ID'].text
url = URI.parse(@endpoint+'/storage/' + image_id)
resource_id = info.elements['ID'].text
url = URI.parse(@endpoint+path + resource_id)
req = Net::HTTP::Put.new(url.path)
req.body = xml
do_request(url, req)
end
def do_request(url, req)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) do |http|
@ -486,25 +342,5 @@ module OCCIClient
return res.body
end
end
######################################################################
# :id VM identifier
######################################################################
def delete_image(id)
url = URI.parse(@endpoint+"/storage/" + id.to_s)
req = Net::HTTP::Delete.new(url.path)
req.basic_auth @occiauth[0], @occiauth[1]
res = CloudClient::http_start(url, @timeout) {|http|
http.request(req)
}
if CloudClient::is_error?(res)
return res
else
return res.body
end
end
end
end
end

View File

@ -30,6 +30,8 @@ require 'ImagePoolOCCI'
require 'UserOCCI'
require 'UserPoolOCCI'
require 'OpenNebulaVNC'
require 'pp'
@ -38,11 +40,14 @@ require 'pp'
# OpenNebula Engine
##############################################################################
COLLECTIONS = ["compute", "instance_type", "network", "storage"]
COLLECTIONS = ["compute", "instance_type", "network", "storage", "user"]
# FLAG that will filter the elements retrieved from the Pools
POOL_FILTER = Pool::INFO_ALL
# Secs to sleep between checks to see if image upload&copy to repo is finished
IMAGE_POLL_SLEEP_TIME = 5
class OCCIServer < CloudServer
# Server initializer
# config_file:: _String_ path of the config file
@ -62,11 +67,11 @@ class OCCIServer < CloudServer
# Prepare the OCCI XML Response
# resource:: _Pool_ or _PoolElement_ that represents a OCCI resource
# [return] _String_,_Integer_ Resource Representation or error, status code
def to_occi_xml(resource, code)
xml_response = resource.to_occi(@base_url)
def to_occi_xml(resource, opts)
xml_response = resource.to_occi(@base_url, opts[:verbose])
return xml_response, 500 if OpenNebula.is_error?(xml_response)
return xml_response, code
return xml_response, opts[:code]
end
############################################################################
@ -87,18 +92,36 @@ class OCCIServer < CloudServer
return xml_resp, 200
end
INSTANCE_TYPE = %q{
<INSTANCE_TYPE href="<%= @base_url %>/instance_type/<%=name%>" name="<%= name %>">
<ID><%= name.to_s %></ID>
<NAME><%= name.to_s %></NAME>
<% opts.each { |elem, value|
next if elem==:template
str = elem.to_s.upcase %>
<<%= str %>><%= value %></<%= str %>>
<% } %>
</INSTANCE_TYPE>
}
def get_instance_types(request)
xml_resp = "<INSTANCE_TYPE_COLLECTION>\n"
@config[:instance_types].each { |k, v|
xml_resp << "\t<INSTANCE_TYPE href=\"#{@base_url}/instance_type/#{k.to_s}\">\n"
xml_resp << "\t\t<NAME>#{k.to_s}</NAME>\n"
v.each { |elem, value|
next if elem==:template
str = elem.to_s.upcase
xml_resp << "\t\t<#{str}>#{value}</#{str}>\n"
}
xml_resp << "\t</INSTANCE_TYPE>\n"
@config[:instance_types].each { |name, opts|
if request.params['verbose']
begin
occi_it = ERB.new(INSTANCE_TYPE)
occi_it = occi_it.result(binding)
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error, CloudServer::HTTP_ERROR_CODE[error.errno]
end
xml_resp << occi_it.gsub(/\n\s*/,'')
else
xml_resp << "\t<INSTANCE_TYPE href=\"#{@base_url}/instance_type/#{name.to_s}\" name=\"#{name}\">\n"
end
}
xml_resp << "</INSTANCE_TYPE_COLLECTION>"
@ -106,6 +129,24 @@ class OCCIServer < CloudServer
return xml_resp, 200
end
def get_instance_type(request, params)
name = params[:id].to_sym
unless @config[:instance_types].keys.include?(name)
error = OpenNebula::Error.new("INSTANCE_TYPE #{name} not found")
return error, 404
else
opts = @config[:instance_types][name]
begin
occi_it = ERB.new(INSTANCE_TYPE)
occi_it = occi_it.result(binding)
rescue Exception => e
error = OpenNebula::Error.new(e.message)
return error, CloudServer::HTTP_ERROR_CODE[error.errno]
end
return occi_it.gsub(/\n\s*/,''), 200
end
end
# Gets the pool representation of COMPUTES
# request:: _Hash_ hash containing the data of the request
@ -122,7 +163,7 @@ class OCCIServer < CloudServer
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
end
return to_occi_xml(vmpool, 200)
return to_occi_xml(vmpool, :status=>200, :verbose=>request.params['verbose'])
end
@ -142,7 +183,7 @@ class OCCIServer < CloudServer
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
end
return to_occi_xml(network_pool, 200)
return to_occi_xml(network_pool, :status=>200, :verbose=>request.params['verbose'])
end
# Gets the pool representation of STORAGES
@ -161,7 +202,7 @@ class OCCIServer < CloudServer
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
end
return to_occi_xml(image_pool, 200)
return to_occi_xml(image_pool, :status=>200, :verbose=>request.params['verbose'])
end
# Gets the pool representation of USERs
@ -178,7 +219,7 @@ class OCCIServer < CloudServer
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
end
return to_occi_xml(user_pool, 200)
return to_occi_xml(user_pool, :status=>200, :verbose=>request.params['verbose'])
end
############################################################################
@ -214,7 +255,7 @@ class OCCIServer < CloudServer
# --- Prepare XML Response ---
vm.info
return to_occi_xml(vm, 201)
return to_occi_xml(vm, :status=>201)
end
# Get the representation of a COMPUTE resource
@ -233,10 +274,9 @@ class OCCIServer < CloudServer
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
end
return to_occi_xml(vm, 200)
return to_occi_xml(vm, :status=>200)
end
# Deletes a COMPUTE resource
# request:: _Hash_ hash containing the data of the request
# [return] _String_,_Integer_ Delete confirmation msg or error,
@ -277,7 +317,7 @@ class OCCIServer < CloudServer
return result, code
else
vm.info
return to_occi_xml(vm, code)
return to_occi_xml(vm, :status=>code)
end
end
@ -307,7 +347,7 @@ class OCCIServer < CloudServer
# --- Prepare XML Response ---
network.info
return to_occi_xml(network, 201)
return to_occi_xml(network, :status=>201)
end
# Retrieves a NETWORK resource
@ -325,7 +365,7 @@ class OCCIServer < CloudServer
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
end
return to_occi_xml(network, 200)
return to_occi_xml(network, :status=>200)
end
# Deletes a NETWORK resource
@ -371,7 +411,7 @@ class OCCIServer < CloudServer
# --- Prepare XML Response ---
vnet.info
return to_occi_xml(vnet, 202)
return to_occi_xml(vnet, :status=>202)
end
############################################################################
@ -409,9 +449,15 @@ class OCCIServer < CloudServer
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
end
# --- Prepare XML Response ---
image.info
return to_occi_xml(image, 201)
#wait until image is ready to return
while (image.state_str == 'LOCKED') && (image['RUNNING_VMS'] == '0') do
sleep IMAGE_POLL_SLEEP_TIME
image.info
end
# --- Prepare XML Response ---
return to_occi_xml(image, :status=>201)
end
# Get a STORAGE resource
@ -430,7 +476,7 @@ class OCCIServer < CloudServer
end
# --- Prepare XML Response ---
return to_occi_xml(image, 200)
return to_occi_xml(image, :status=>200)
end
# Deletes a STORAGE resource (Not yet implemented)
@ -484,7 +530,7 @@ class OCCIServer < CloudServer
# --- Prepare XML Response ---
image.info
return to_occi_xml(image, 202)
return to_occi_xml(image, :status=>202)
end
# Get the representation of a USER
@ -503,6 +549,34 @@ class OCCIServer < CloudServer
return rc, CloudServer::HTTP_ERROR_CODE[rc.errno]
end
return to_occi_xml(user, 200)
return to_occi_xml(user, :status=>200)
end
############################################################################
# VNC Methods
############################################################################
def startvnc(id,config)
vm = VirtualMachineOCCI.new(VirtualMachine.build_xml(id), @client)
rc = vm.info
if OpenNebula.is_error?(rc)
error = "Error starting VNC session, "
error << "could not retrieve Virtual Machine"
return [404, error]
end
vnc_proxy = OpenNebulaVNC.new(config,{:json_errors => false})
return vnc_proxy.start(vm)
end
def stopvnc(pipe)
begin
OpenNebulaVNC.stop(pipe)
rescue Exception => e
return [500, e.message]
end
return [200,nil]
end
end

View File

@ -27,6 +27,7 @@ class UserOCCI < User
<USER href="<%= base_url %>/user/<%= self.id.to_s %>">
<ID><%= self.id.to_s %></ID>
<NAME><%= self.name %></NAME>
<GROUP><%= self['GNAME'] %></GROUP>
<QUOTA>
<% user_quota.each { |key,value|
key_s = key.to_s.upcase
@ -50,7 +51,7 @@ class UserOCCI < User
end
# Creates the OCCI representation of a User
def to_occi(base_url)
def to_occi(base_url, verbose=false)
quota = Quota.new
user_usage = quota.get_usage(self.id, nil, FORCE_USAGE)
user_usage.delete(:uid)

View File

@ -14,22 +14,23 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
require 'OpenNebula'
include OpenNebula
require 'UserOCCI'
class UserPoolOCCI < UserPool
OCCI_USER_POOL = %q{
<USER_COLLECTION>
<% self.each{ |user| %>
<% if verbose %>
<%= user.to_occi(base_url) %>
<% else %>
<USER href="<%= base_url %>/user/<%= user.id.to_s %>" name="<%= user.name %>"/>
<% end %>
<% } %>
</USER_COLLECTION>
}
# Creates the OCCI representation of a User Pool
def to_occi(base_url)
def to_occi(base_url, verbose=false)
begin
occi = ERB.new(OCCI_USER_POOL)
occi_text = occi.result(binding)
@ -40,4 +41,8 @@ class UserPoolOCCI < UserPool
return occi_text.gsub(/\n\s*/,'')
end
def factory(element_xml)
UserOCCI.new(element_xml,@client)
end
end

View File

@ -22,6 +22,8 @@ class VirtualMachineOCCI < VirtualMachine
OCCI_VM = %q{
<COMPUTE href="<%= base_url %>/compute/<%= self.id.to_s %>">
<ID><%= self.id.to_s%></ID>
<USER href="<%= base_url %>/user/<%= self['UID'] %>" name="<%= self['UNAME'] %>"/>
<GROUP><%= self['GNAME'] %></GROUP>
<CPU><%= self['TEMPLATE/CPU'] %></CPU>
<MEMORY><%= self['TEMPLATE/MEMORY'] %></MEMORY>
<NAME><%= self.name%></NAME>
@ -120,7 +122,7 @@ class VirtualMachineOCCI < VirtualMachine
end
# Creates the VMI representation of a Virtual Machine
def to_occi(base_url)
def to_occi(base_url, verbose=false)
begin
occi_vm = ERB.new(OCCI_VM)
occi_vm_text = occi_vm.result(binding)

View File

@ -14,22 +14,24 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
require 'OpenNebula'
include OpenNebula
require 'VirtualMachineOCCI'
class VirtualMachinePoolOCCI < VirtualMachinePool
OCCI_VM_POOL = %q{
<COMPUTE_COLLECTION>
<% self.each{ |vm| %>
<% self.each{ |vm| %>
<% if verbose %>
<%= vm.to_occi(base_url) %>
<% else %>
<COMPUTE href="<%= base_url %>/compute/<%= vm.id.to_s %>" name="<%= vm.name %>"/>
<% end %>
<% } %>
</COMPUTE_COLLECTION>
}
# Creates the OCCI representation of a Virtual Machine Pool
def to_occi(base_url)
def to_occi(base_url, verbose=false)
begin
occi = ERB.new(OCCI_VM_POOL)
occi_text = occi.result(binding)
@ -40,5 +42,9 @@ class VirtualMachinePoolOCCI < VirtualMachinePool
return occi_text.gsub(/\n\s*/,'')
end
def factory(element_xml)
VirtualMachineOCCI.new(element_xml,@client)
end
end

View File

@ -24,6 +24,8 @@ class VirtualNetworkOCCI < VirtualNetwork
<NETWORK href="<%= base_url %>/network/<%= self.id.to_s %>">
<ID><%= self.id.to_s %></ID>
<NAME><%= self.name %></NAME>
<USER href="<%= base_url %>/user/<%= self['UID'] %>" name="<%= self['UNAME'] %>"/>
<GROUP><%= self['GNAME'] %></GROUP>
<% if self['TEMPLATE/DESCRIPTION'] != nil %>
<DESCRIPTION><%= self['TEMPLATE/DESCRIPTION'] %></DESCRIPTION>
<% end %>
@ -52,7 +54,7 @@ class VirtualNetworkOCCI < VirtualNetwork
end
# Creates the OCCI representation of a Virtual Network
def to_occi(base_url)
def to_occi(base_url, verbose=false)
network_address = nil
network_size = nil

View File

@ -14,22 +14,25 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
require 'OpenNebula'
include OpenNebula
require 'VirtualNetworkOCCI'
class VirtualNetworkPoolOCCI < VirtualNetworkPool
OCCI_NETWORK_POOL = %q{
<NETWORK_COLLECTION>
<% self.each{ |vn| %>
<% self.each{ |vn| %>
<% if verbose %>
<%= vn.to_occi(base_url) %>
<% else %>
<NETWORK href="<%= base_url %>/network/<%= vn.id.to_s %>" name="<%= vn.name %>"/>
<% end %>
<% } %>
</NETWORK_COLLECTION>
}
# Creates the OCCI representation of a Virtual Machine Pool
def to_occi(base_url)begin
def to_occi(base_url, verbose=false)
begin
occi = ERB.new(OCCI_NETWORK_POOL)
occi_text = occi.result(binding)
rescue Exception => e
@ -39,4 +42,8 @@ class VirtualNetworkPoolOCCI < VirtualNetworkPool
return occi_text.gsub(/\n\s*/,'')
end
def factory(element_xml)
VirtualNetworkOCCI.new(element_xml,@client)
end
end

View File

@ -305,11 +305,31 @@ get '/user/:id' do
treat_response(result,rc)
end
get '/instance_type/:id' do
result,rc = @occi_server.get_instance_type(request, params)
treat_response(result,rc)
end
##############################################
## UI
## OCCI UI (Self-Service)
##############################################
post '/config' do
get '/ui/config' do
wss = settings.config[:vnc_proxy_support_wss]
wss = (wss == true || wss == "yes" || wss == "only" ? "yes" : "no")
vnc = settings.config[:vnc_enable] ? "yes" : "no"
config = "<UI_CONFIGURARION>"
config << " <LANG>#{session[:lang]}</LANG>"
config << " <WSS>#{wss}</WSS>"
config << " <VNC>#{vnc}</VNC>"
config << "</UI_CONFIGURARION>"
return [200, config]
end
post '/ui/config' do
begin
body = JSON.parse(request.body.read)
rescue
@ -321,6 +341,8 @@ post '/config' do
when "lang" then session[:lang]=value
end
end
return 200
end
get '/ui/login' do
@ -349,9 +371,60 @@ get '/ui' do
end
post '/ui/upload' do
file = Tempfile.new('uploaded_image')
FileUtils.cp(request.env['rack.input'].path,file.path)
request.params['file'] = file.path #so we can re-use occi post_storage()
#so we can re-use occi post_storage()
request.params['file'] = {:tempfile => request.env['rack.input']}
result,rc = @occi_server.post_storage(request)
treat_response(result,rc)
end
post '/ui/startvnc/:id' do
if !settings.config[:vnc_enable]
return [403, "VNC sessions are disabled"]
end
vm_id = params[:id]
vnc_hash = session['vnc']
if !vnc_hash
session['vnc'] = {}
elsif vnc_hash[vm_id]
#return existing information
info = vnc_hash[vm_id].clone
info.delete(:pipe)
return [200, info.to_json]
end
rc = @occi_server.startvnc(vm_id, settings.config)
if rc[0] == 200
info = rc[1]
session['vnc'][vm_id] = info.clone
info.delete(:pipe)
rc = [200, info.to_json]
end
return rc
end
post '/ui/stopvnc/:id' do
if !settings.config[:vnc_enable]
return [403, "VNC sessions are disabled"]
end
vm_id = params[:id]
vnc_hash = session['vnc']
if !vnc_hash || !vnc_hash[vm_id]
return [403, "It seems there is no VNC proxy running for this machine"]
end
rc = @occi_server.stopvnc(vnc_hash[vm_id][:pipe])
if rc[0] == 200
session['vnc'].delete(vm_id)
end
return rc
end

View File

@ -45,7 +45,7 @@ function setLang(lang_str){
if (('localStorage' in window) && (window['localStorage'] !== null)){
localStorage['lang']=lang_str;
};
$.post('config',JSON.stringify({lang:lang_str}),function(){window.location.href = "./ui"});
$.post('ui/config',JSON.stringify({lang:lang_str}),function(){window.location.href = "./ui"});
};
$(document).ready(function(){

View File

@ -342,6 +342,31 @@ var OCCI = {
}
},
"Config": {
"resource": "CONFIG",
"list": function(params){
var callback = params.success;
var callback_error = params.error;
var resource = OCCI.Config.resource;
var request = OCCI.Helper.request(resource,"list");
$.ajax({
url: "ui/config",
type: "GET",
dataType: "xml ONEjson",
success: function(response){
return callback ? callback(request, response) : null;
},
error: function(response){
return callback_error ?
callback_error(request, OCCI.Error(response)) : null;
}
});
}
},
"Network": {
"resource": "NETWORK",
@ -413,7 +438,7 @@ var OCCI = {
params.data.body = '<DISK id="'+disk_id+'"><SAVE_AS name="'+im_name+'" /></DISK>';
OCCI.Action.update(params,OCCI.VM.resource,"saveas");
},
/* "vnc" : function(params,startstop){
"vnc" : function(params,startstop){
var callback = params.success;
var callback_error = params.error;
var id = params.data.id;
@ -423,7 +448,7 @@ var OCCI = {
var action = OCCI.Helper.action(method);
var request = OCCI.Helper.request(resource,method, id);
$.ajax({
url: "vm/" + id + "/" + method,
url: "ui/" + method + "/" + id,
type: "POST",
dataType: "json",
success: function(response){
@ -440,13 +465,16 @@ var OCCI = {
},
"stopvnc" : function(params){
OCCI.VM.vnc(params,"stopvnc");
},
/*
"monitor" : function(params){
OCCI.Action.monitor(params,OCCI.VM.resource,false);
},
"monitor_all" : function(params){
OCCI.Action.monitor(params,OCCI.VM.resource,true);
}*/
}
*/
},
"Image": {

View File

@ -15,16 +15,19 @@
/* -------------------------------------------------------------------------- */
/*Virtual Machines tab plugin*/
//var INCLUDE_URI = "vendor/noVNC/include/";
var INCLUDE_URI = "vendor/noVNC/include/";
//var VM_HISTORY_LENGTH = 40;
/*
function loadVNC(){
var script = '<script src="vendor/noVNC/include/vnc.js"></script>';
document.write(script);
}
loadVNC();
var vnc_enable=false;
var use_wss=false;
/*
var vm_graphs = [
{ title : tr("CPU"),
monitor_resources : "cpu_usage",
@ -264,7 +267,6 @@ var vm_actions = {
error: onError
},
/*
"VM.startvnc" : {
type: "single",
call: OCCI.VM.startvnc,
@ -280,6 +282,7 @@ var vm_actions = {
notify: true
},
/*
"VM.monitor" : {
type: "monitor",
call : OCCI.VM.monitor,
@ -540,6 +543,10 @@ function updateVMInfo(request,vm){
<td class="key_td">'+tr("Memory")+'</td>\
<td class="value_td">'+vm_info.MEMORY+'</td>\
</tr>\
<tr>\
<td class="key_td">'+tr("Launch VNC session")+'</td>\
<td class="value_td">'+vncIcon(vm_info)+'</td>\
</tr>\
</tbody>\
</table>\
<div class="form_buttons">\
@ -940,7 +947,7 @@ function setVMAutorefresh(){
},INTERVAL+someTime());
}
/*
function updateVNCState(rfb, state, oldstate, msg) {
var s, sb, cad, klass;
s = $D('VNC_status');
@ -1016,7 +1023,7 @@ function setupVNC(){
Sunstone.runAction("VM.stopvnc",id);
});
$('.vnc',main_tabs_context).live("click",function(){
$('.vnc').live("click",function(){
//Which VM is it?
var id = $(this).attr('vm_id');
//Set attribute to dialog
@ -1029,7 +1036,7 @@ function setupVNC(){
function vncCallback(request,response){
rfb = new RFB({'target': $D('VNC_canvas'),
'encrypt': false,
'encrypt': use_wss,
'true_color': true,
'local_cursor': true,
'shared': true,
@ -1049,6 +1056,20 @@ function vncCallback(request,response){
}
function vncIcon(vm){
var gr_icon;
if (vnc_enable){
gr_icon = '<a class="vnc" href="#" vm_id="'+vm.ID+'">';
gr_icon += '<img src="images/vnc_on.png" alt=\"'+tr("Open VNC Session")+'\" /></a>';
}
else {
gr_icon = '<img src="images/vnc_off.png" alt=\"'+tr("VNC Disabled")+'\" />';
}
return gr_icon;
}
/*
function vncIcon(vm){
var graphics = vm.TEMPLATE.GRAPHICS;
var state = vm.STATE;
@ -1063,6 +1084,9 @@ function vncIcon(vm){
return gr_icon;
}
*/
/*
function vmMonitorError(req,error_json){
var message = error_json.error.message;
var info = req.request.data[0].monitor;
@ -1070,9 +1094,9 @@ function vmMonitorError(req,error_json){
var id_suffix = labels.replace(/,/g,'_');
var id = '#vm_monitor_'+id_suffix;
$('#vm_monitoring_tab '+id).html('<div style="padding-left:20px;">'+message+'</div>');
}
}*/
*/
// At this point the DOM is ready and the sunstone.js ready() has been run.
$(document).ready(function(){
@ -1102,7 +1126,7 @@ $(document).ready(function(){
//setupCreateVMDialog();
setupSaveasDialog();
setVMAutorefresh();
//setupVNC();
setupVNC();
initCheckAllBoxes(dataTable_vMachines);
tableCheckboxesListener(dataTable_vMachines);

View File

@ -41,24 +41,46 @@ var config_tab_content =
</tr>\
</table></form>';
var config_actions = {
"Config.list" : {
type : 'list',
call : OCCI.Config.list,
callback : updateConfig,
error : onError
},
};
var config_tab = {
title: tr("Configuration"),
content: config_tab_content
}
Sunstone.addActions(config_actions);
Sunstone.addMainTab('config_tab',config_tab);
function updateConfig(request, response){
var config = response;
//These two variables defined in compute.js
vnc_enable = config['VNC'] == 'true' || config['VNC'] == 'yes' ? true : false;
use_wss = config['WSS'] == 'true' || config['WSS'] == 'yes'? true : false;
};
$(document).ready(function(){
if (lang)
$('table#config_table #lang_sel option[value="'+lang+'"]').attr('selected','selected');
$('table#config_table #lang_sel').change(function(){
setLang($(this).val());
});
Sunstone.runAction('Config.list');
$('#li_config_tab').click(function(){
hideDialog();
});
$('div#logo img').attr('src',logo_small);
//Set lang to the right value
if (lang)
$('table#config_table #lang_sel option[value="'+lang+'"]').attr('selected','selected');
//Listen to changes in language
$('table#config_table #lang_sel').change(function(){
setLang($(this).val());
});
//Vendor customization, change small logo
$('div#logo img').attr('src',logo_small);
});

View File

@ -478,7 +478,7 @@ function popUpCreateImageDialog(){
multiple: false,
params: {},
showMessage: function(message){
notifyMessage(message);
//notifyMessage(message);
},
onSubmit: function(id, fileName){
var xml = json2xml(img_obj,"STORAGE");

View File

@ -75,7 +75,7 @@
</div>
<div id="footer" class="ui-layout-south">
Copyright 2002-2012 &copy; OpenNebula Project Leads (<a href="http://opennebula.org" target="_blank">OpenNebula.org</a>). All Rights Reserved. OpenNebula 3.2.0
Copyright 2002-2012 &copy; OpenNebula Project Leads (<a href="http://opennebula.org" target="_blank">OpenNebula.org</a>). All Rights Reserved. OpenNebula 3.3.0
</div>

View File

@ -86,7 +86,7 @@ EOF
#-------------------------------------------------------------------------------
function fs_du {
if [ -d "$1" ]; then
SIZE=`du -s "$1" | cut -f1`
SIZE=`du -sb "$1" | cut -f1`
error=$?
else
SIZE=`stat -c %s "$1"`

View File

@ -330,7 +330,7 @@ void LifeCycleManager::deploy_failure_action(int vid)
vmpool->update_history(vm);
vm->log("LCM", Log::INFO, "Fail to life migrate VM."
vm->log("LCM", Log::INFO, "Fail to live migrate VM."
" Assuming that the VM is still RUNNING (will poll VM).");
//----------------------------------------------------

View File

@ -137,56 +137,6 @@ public class VirtualMachine extends PoolElement{
return client.call(ALLOCATE, description);
}
/**
* Allocates a new VM in OpenNebula from a registered Template.
*
* @param client XML-RPC Client.
* @param templateId The source Template's ID
* @param newName Name for the new VM, replaces the Template's one.
* Can be null.
* @return If successful the message contains the associated
* id generated for this VM.
*/
public static OneResponse allocateFromTemplate(Client client,
int templateId, String newName)
{
String template = "TEMPLATE_ID = " + templateId;
if( newName != null )
{
template += "\nNAME = " + newName;
}
return allocate(client, template);
}
/**
* Allocates a new VM in OpenNebula from a registered Template.
*
* @param client XML-RPC Client.
* @param templateId The source Template's ID
* @return If successful the message contains the associated
* id generated for this VM.
*/
public static OneResponse allocateFromTemplate(Client client,
int templateId)
{
return allocateFromTemplate(client, templateId, null);
}
/**
* Allocates a new VM in OpenNebula from a registered Template.
*
* @param client XML-RPC Client.
* @param template The source Template.
* @return If successful the message contains the associated
* id generated for this VM.
*/
public static OneResponse allocateFromTemplate(Client client,
Template template)
{
return allocateFromTemplate(client, template.id());
}
/**
* Retrieves the information of the given VM.
*

View File

@ -247,17 +247,6 @@ public class TemplateTest
assertTrue( res.isError() );
}
@Test
public void allocateFromTemplate()
{
res = template.info();
assertTrue( !res.isError() );
res = VirtualMachine.allocateFromTemplate(client, template);
assertTrue( !res.isError() );
assertTrue( res.getMessage().equals("0") );
}
@Test
public void chown()
{

View File

@ -0,0 +1,28 @@
# -------------------------------------------------------------------------- *
# 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 Migrator
def db_version
"3.3.0"
end
def one_version
"OpenNebula 3.3.0"
end
def up
return true
end
end

View File

@ -60,7 +60,7 @@
</div>
</div>
<div id="footer" class="ui-layout-south">
Copyright 2002-2012 &copy; OpenNebula Project Leads (<a href="http://opennebula.org" target="_blank">OpenNebula.org</a>). All Rights Reserved. OpenNebula 3.2.0
Copyright 2002-2012 &copy; OpenNebula Project Leads (<a href="http://opennebula.org" target="_blank">OpenNebula.org</a>). All Rights Reserved. OpenNebula 3.3.0
</div>

View File

@ -0,0 +1,103 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2012, 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. #
#--------------------------------------------------------------------------- #
require 'json'
require 'OpenNebula'
#
# This class provides support for launching and stopping a websockify proxy
#
class OpenNebulaVNC
def initialize(config, opt={:json_errors => true})
@proxy_path = config[:vnc_proxy_path]
@proxy_base_port = config[:vnc_proxy_base_port].to_i
@wss = config[:vnc_proxy_support_wss]
if (@wss == "yes") || (@wss == "only") || (@wss == true)
@enable_wss = true
@cert = config[:vnc_proxy_cert]
@key = config[:vnc_proxy_key]
else
@enable_wss = false
end
@options = opt
end
# Start a VNC proxy
def start(vm_resource)
# Check configurations and VM attributes
if @proxy_path == nil || @proxy_path.empty?
return error(403,"VNC proxy not configured")
end
if vm_resource['LCM_STATE'] != "3"
return error(403,"VM is not running")
end
if vm_resource['TEMPLATE/GRAPHICS/TYPE'] != "vnc"
return error(403,"VM has no VNC configured")
end
# Proxy data
host = vm_resource['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']
vnc_port = vm_resource['TEMPLATE/GRAPHICS/PORT']
proxy_port = @proxy_base_port + vnc_port.to_i
proxy_options = ""
if @enable_wss
proxy_options << " --cert #{@cert}"
proxy_options << " --key #{@key}" if @key && @key.size > 0
proxy_options << " --ssl-only" if @wss == "only"
end
cmd ="#{@proxy_path} #{proxy_options} #{proxy_port} #{host}:#{vnc_port}"
begin
$stderr.puts("Starting vnc proxy: #{cmd}")
pipe = IO.popen(cmd)
rescue Exception => e
return [500, OpenNebula::Error.new(e.message).to_json]
end
vnc_pw = vm_resource['TEMPLATE/GRAPHICS/PASSWD']
info = {:pipe => pipe, :port => proxy_port, :password => vnc_pw}
return [200, info]
end
# Stop a VNC proxy handle exceptions outside
def self.stop(pipe)
Process.kill('KILL',pipe.pid)
pipe.close
end
private
def error(code, msg)
if @options[:json_errors]
return [code,OpenNebula::Error.new(msg).to_json]
else
return [code,msg]
end
end
end

View File

@ -16,8 +16,20 @@
:core_auth: cipher
# VNC Configuration
# base_port: base_port + vnc_port of the VM is the port where the
# proxy will listen for VNC session connections to that VM.
# vnc_proxy_path: path to the websockets proxy (set by install_novnc.sh)
# support_wss: no | yes | only. For yes and only, provide path to
# cert and key. "yes" means both ws and wss connections will be
# supported.
# vnc_proxy_cert: Certificate to encrypt wss connections.
# vnc_proxy_key: Key for wss connections. Only necessary if not included in cert.
:vnc_proxy_base_port: 29876
:novnc_path:
:vnc_proxy_path:
:vnc_proxy_support_wss: no
:vnc_proxy_cert:
:vnc_proxy_key:
# Default language setting
:lang: en_US

View File

@ -18,11 +18,17 @@ require 'OpenNebulaJSON'
include OpenNebulaJSON
require 'acct/watch_client'
require 'OpenNebulaVNC'
require 'OpenNebulaJSON/JSONUtils'
include JSONUtils
class SunstoneServer
# FLAG that will filter the elements retrieved from the Pools
POOL_FILTER = Pool::INFO_ALL
# Secs to sleep between checks to see if image upload to repo is finished
IMAGE_POLL_SLEEP_TIME = 5
def initialize(client)
@client = client
end
@ -112,6 +118,31 @@ class SunstoneServer
end
end
############################################################################
#
############################################################################
def upload(template, file_path)
image_hash = parse_json(template, 'image')
image_hash['PATH'] = file_path
new_template = {:image => image_hash}.to_json
image = ImageJSON.new(Image.build_xml, @client)
rc = image.create(new_template)
if OpenNebula.is_error?(rc)
return [500, rc.to_json]
end
image.info
#wait until image is ready to return
while (image.state_str == 'LOCKED') && (image['RUNNING_VMS'] == '0') do
sleep IMAGE_POLL_SLEEP_TIME
image.info
end
return [201, image.to_json]
end
############################################################################
#
############################################################################
@ -146,37 +177,6 @@ class SunstoneServer
end
end
############################################################################
#
############################################################################
def get_configuration(user_id)
if user_id != "0"
return [401, ""]
end
one_config = VAR_LOCATION + "/config"
config = Hash.new
begin
cfg = File.read(one_config)
rescue Exception => e
error = Error.new("Error reading config: #{e.inspect}")
return [500, error.to_json]
end
cfg.lines do |line|
m=line.match(/^([^=]+)=(.*)$/)
if m
name=m[1].strip.upcase
value=m[2].strip
config[name]=value
end
end
return [200, config.to_json]
end
############################################################################
#
############################################################################
@ -201,7 +201,6 @@ class SunstoneServer
end
end
########################################################################
# VNC
########################################################################
@ -211,50 +210,16 @@ class SunstoneServer
return [404, resource.to_json]
end
if resource['LCM_STATE'] != "3"
error = OpenNebula::Error.new("VM is not running")
return [403, error.to_json]
end
if resource['TEMPLATE/GRAPHICS/TYPE'] != "vnc"
error = OpenNebula::Error.new("VM has no VNC configured")
return [403, error.to_json]
end
# The VM host and its VNC port
host = resource['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']
vnc_port = resource['TEMPLATE/GRAPHICS/PORT']
# The noVNC proxy_port
proxy_port = config[:vnc_proxy_base_port].to_i + vnc_port.to_i
begin
novnc_cmd = "#{config[:novnc_path]}/utils/wsproxy.py"
novnc_exec = "#{novnc_cmd} #{proxy_port} #{host}:#{vnc_port}"
$stderr.puts("Starting vnc proxy: #{novnc_exec}")
pipe = IO.popen(novnc_exec)
rescue Exception => e
error = Error.new(e.message)
return [500, error.to_json]
end
vnc_pw = resource['TEMPLATE/GRAPHICS/PASSWD']
info = {:pipe => pipe, :port => proxy_port, :password => vnc_pw}
return [200, info]
vnc_proxy = OpenNebulaVNC.new(config)
return vnc_proxy.start(resource)
end
############################################################################
#
############################################################################
def stopvnc(id,pipe)
resource = retrieve_resource("vm", id)
if OpenNebula.is_error?(resource)
return [404, resource.to_json]
end
def stopvnc(pipe)
begin
Process.kill('KILL',pipe.pid)
pipe.close
OpenNebulaVNC.stop(pipe)
rescue Exception => e
error = Error.new(e.message)
return [500, error.to_json]
@ -266,8 +231,7 @@ class SunstoneServer
############################################################################
#
############################################################################
def get_monitoring(id, resource, monitor_resources, gid)
def get_monitoring(id, resource, monitor_resources, opts={})
watch_client = case resource
when "vm","VM"
OneWatchClient::VmWatchClient.new
@ -278,13 +242,16 @@ class SunstoneServer
return [200, error.to_json]
end
filter = {}
filter[:uid] = opts[:uid] if opts[:gid]!="0"
columns = monitor_resources.split(',')
columns.map!{|e| e.to_sym}
if id
rc = watch_client.resource_monitoring(id.to_i, columns)
rc = watch_client.resource_monitoring(id.to_i, columns, filter)
else
rc = watch_client.total_monitoring(columns)
rc = watch_client.total_monitoring(columns, filter)
end
if rc.nil?
@ -295,18 +262,11 @@ class SunstoneServer
return [200, rc.to_json]
end
############################################################################
#
############################################################################
############################################################################
#
############################################################################
private
############################################################################
#
############################################################################
def retrieve_resource(kind, id)
resource = case kind
when "group" then GroupJSON.new_with_id(id, @client)

View File

@ -33,6 +33,12 @@ var config_tab_content =
</select>\
</td>\
</tr>\
<tr>\
<td class="key_td">' + tr("Secure websockets connection") + '</td>\
<td class="value_td">\
<input id="wss_checkbox" type="checkbox" value="yes" />\
</td>\
</tr>\
</table>\
\
</div>\
@ -41,18 +47,74 @@ var config_tab_content =
</tr>\
</table></form>';
var config_actions = {
"Config.list" : {
type: "list",
call: OpenNebula.Config.list,
callback: updateConfig,
error: onError
},
};
var config_tab = {
title: tr("Configuration"),
content: config_tab_content
}
Sunstone.addActions(config_actions);
Sunstone.addMainTab('config_tab',config_tab);
function updateConfig(request,response){
var config = response['user_config'];
//Set wss checkbox to correct value
if (config["wss"] == "yes"){
$('table#config_table input#wss_checkbox').attr('checked','checked');
};
};
function updateWss(){
var user_info_req = {
data : {
id: uid,
},
success: function(req,user_json) {
var template = user_json.USER.TEMPLATE;
var template_str="";
template['VNC_WSS']=
$('#config_table #wss_checkbox').is(':checked') ? "yes" : "no";
//convert json to ONE template format - simple conversion
$.each(template,function(key,value){
template_str += (key + '=' + '"' + value + '"\n');
});
var request = {
data: {
id: uid,
extra_param: template_str
},
error: onError
};
OpenNebula.User.update(request);
},
};
OpenNebula.User.show(user_info_req);
$.post('config',JSON.stringify({wss : ($('#config_table #wss_checkbox').is(':checked') ? "yes" : "no")}));
};
$(document).ready(function(){
Sunstone.runAction('Config.list');
//Set the language select to correct value
if (lang)
$('table#config_table #lang_sel option[value="'+lang+'"]').attr('selected','selected');
//Listener to change language
$('table#config_table #lang_sel').change(function(){
setLang($(this).val());
});
//Listener to wss change
$('table#config_table #wss_checkbox').change(updateWss);
});

View File

@ -85,11 +85,12 @@ var create_host_tmpl =
<div class="manager clear" id="vnm_mads">\
<label>Virtual Network Manager:</label>\
<select id="vnm_mad" name="vn">\
<option value="dummy">Default (dummy)</option>\
<option value="dummy">' + tr("Default (dummy)") +'</option>\
<option value="fw">Firewall</option>\
<option value="802.1Q">802.1Q</option>\
<option value="ebtables">Ebtables</option>\
<option value="ovswitch">Open vSwitch</option>\
<option value="vmware">VMware</option>\
</select>\
</div>\
<div class="manager clear" id="tm_mads">\

View File

@ -100,14 +100,21 @@ var create_image_tmpl =
</fieldset>\
<fieldset>\
<div class="" id="src_path_select">\
<label style="height:3em;">'+tr("Path vs. source")+':</label>\
<label style="height:4em;">'+tr("Image location")+':</label>\
\
<input type="radio" name="src_path" id="path_img" value="path" />\
<label style="float:none">'+tr("Provide a path")+'</label><br />\
\
<input type="radio" name="src_path" id="source_img" value="source" />\
<label style="float:none">'+tr("Provide a source")+'</label><br />\
\
<input type="radio" name="src_path" id="upload_img" value="upload" />\
<label style="float:none">'+tr("Upload")+'</label><br />\
\
<input type="radio" name="src_path" id="datablock_img" value="datablock" />\
<label style="float:none;vertical-align:top">'+tr("Create an empty datablock")+'</label>\
<div class="tip">'+tr("Please choose path if you have a file-based image. Choose source otherwise or create an empty datablock disk.")+'</div><br />\
\
</div>\
<div class="img_param">\
<label for="img_path">'+tr("Path")+':</label>\
@ -129,6 +136,11 @@ var create_image_tmpl =
<input type="text" name="img_fstype" id="img_fstype" />\
<div class="tip">'+tr("Type of file system to be built. This can be any value understood by mkfs unix command.")+'</div>\
</div>\
<div class="img_param" id="upload_div">\
<label for="file-uploader" >'+tr("Upload file")+':</label>\
<div id="file-uploader">\
</div><div class="clear" />\
</div>\
</fieldset>\
<fieldset>\
<div class="">\
@ -666,6 +678,7 @@ function updateImageInfo(request,img){
function setupCreateImageDialog(){
dialogs_context.append('<div title="'+tr("Create Image")+'" id="create_image_dialog"></div>');
$create_image_dialog = $('#create_image_dialog',dialogs_context);
var dialog = $create_image_dialog;
dialog.html(create_image_tmpl);
@ -694,12 +707,12 @@ function setupCreateImageDialog(){
default:
$('#datablock_img',context).attr('disabled','disabled');
$('#path_img',context).attr('checked','checked');
$('#img_source,#img_fstype,#img_size',context).parent().hide();
$('#img_source,#img_fstype,#img_size,#file-uploader',context).parent().hide();
$('#img_path',context).parent().show();
}
});
$('#img_source,#img_fstype,#img_size',dialog).parent().hide();
$('#img_source,#img_fstype,#img_size,#file-uploader',dialog).parent().hide();
$('#path_img',dialog).attr('checked','checked');
$('#img_path',dialog).parent().addClass("img_man");
@ -708,24 +721,30 @@ function setupCreateImageDialog(){
var value = $(this).val();
switch (value){
case "path":
$('#img_source,#img_fstype,#img_size',context).parent().hide();
$('#img_source,#img_fstype,#img_size',context).parent().removeClass("img_man");
$('#img_source,#img_fstype,#img_size,#file-uploader',context).parent().hide();
$('#img_source,#img_fstype,#img_size,#file-uploader',context).parent().removeClass("img_man");
$('#img_path',context).parent().show();
$('#img_path',context).parent().addClass("img_man");
break;
case "source":
$('#img_path,#img_fstype,#img_size',context).parent().hide();
$('#img_path,#img_fstype,#img_size',context).parent().removeClass("img_man");
$('#img_path,#img_fstype,#img_size,#file-uploader',context).parent().hide();
$('#img_path,#img_fstype,#img_size,#file-uploader',context).parent().removeClass("img_man");
$('#img_source',context).parent().show();
$('#img_source',context).parent().addClass("img_man");
break;
case "datablock":
$('#img_source,#img_path',context).parent().hide();
$('#img_source,#img_path',context).parent().removeClass("img_man");
$('#img_source,#img_path,#file-uploader',context).parent().hide();
$('#img_source,#img_path,#file-uploader',context).parent().removeClass("img_man");
$('#img_fstype,#img_size',context).parent().show();
$('#img_fstype,#img_size',context).parent().addClass("img_man");
break;
}
case "upload":
$('#img_path,#img_source,#img_fstype,#img_size',context).parent().hide();
$('#img_path,#img_source,#img_fstype,#img_size',context).parent().removeClass("img_man");
$('#file-uploader',context).parent().show();
$('#file-uploader',context).parent().addClass("img_man");
break;
};
});
@ -752,9 +771,70 @@ function setupCreateImageDialog(){
}
);
$('#upload-progress',dialog).css({
border: "1px solid #AAAAAA",
position: "relative",
// bottom: "29px",
width: "258px",
// left: "133px",
height: "15px",
display: "inline-block",
});
$('#upload-progress div',dialog).css("border","1px solid #AAAAAA");
var img_obj;
var uploader = new qq.FileUploaderBasic({
button: $('#file-uploader',$create_image_dialog)[0],
action: 'upload',
multiple: false,
params: {},
showMessage: function(message){
//notifyMessage(message);
},
onSubmit: function(id, fileName){
uploader.setParams({
img : JSON.stringify(img_obj),
file: fileName
});
var pos_top = $(window).height() - 120;
var pos_left = 140;
var pb_dialog = $('<div id="pb_dialog" title="'+
tr("Uploading...")+'">'+
'<div id="upload-progress"></div>'+
'</div>').dialog({
draggable:true,
modal:false,
resizable:false,
buttons:{},
width: 460,
minHeight: 50,
position: [pos_left, pos_top]
});
$('#upload-progress',pb_dialog).progressbar({value:0});
},
onProgress: function(id, fileName, loaded, total){
$('div#pb_dialog #upload-progress').progressbar("option","value",Math.floor(loaded*100/total));
},
onComplete: function(id, fileName, responseJSON){
notifyMessage("Image uploaded correctly");
$('div#pb_dialog').dialog('destroy');
Sunstone.runAction("Image.list");
return false;
},
onCancel: function(id, fileName){
},
});
var file_input = false;
uploader._button._options.onChange = function(input) {
file_input = input; return false;
};
$('#create_image_form_easy',dialog).submit(function(){
var exit = false;
var upload = false;
$('.img_man',this).each(function(){
if (!$('input',this).val().length){
notifyError(tr("There are mandatory parameters missing"));
@ -805,6 +885,9 @@ function setupCreateImageDialog(){
img_json["SIZE"] = size;
img_json["FSTYPE"] = fstype;
break;
case "upload":
upload=true;
break;
}
//Time to add custom attributes
@ -815,8 +898,13 @@ function setupCreateImageDialog(){
});
var obj = { "image" : img_json };
Sunstone.runAction("Image.create", obj);
img_obj = { "image" : img_json };
if (upload){
uploader._onInputChange(file_input);
} else {
Sunstone.runAction("Image.create", img_obj);
};
$create_image_dialog.dialog('close');
return false;
@ -831,6 +919,9 @@ function setupCreateImageDialog(){
}
function popUpCreateImageDialog(){
$('#file-uploader input',$create_image_dialog).removeAttr("style");
$('#file-uploader input',$create_image_dialog).attr('style','margin:0;width:256px!important');
$create_image_dialog.dialog('open');
}

View File

@ -1227,7 +1227,7 @@ function setupVNC(){
function vncCallback(request,response){
rfb = new RFB({'target': $D('VNC_canvas'),
'encrypt': false,
'encrypt': $('#config_table #wss_checkbox').is(':checked'),
'true_color': true,
'local_cursor': true,
'shared': true,

View File

@ -51,8 +51,25 @@ var create_vn_tmpl =
<input type="text" name="name" id="name" /><br />\
</fieldset>\
<fieldset>\
<label for="network_mode">'+tr("Network mode")+':</label>\
<select name="network_mode" id="network_mode">\
<option value="default">'+tr("Default")+'</option>\
<option value="802.1Q">'+tr("802.1Q")+'</option>\
<option value="etables">'+tr("Etables")+'</option>\
<option value="openvswitch">'+tr("Open vSwitch")+'</option>\
<option value="vmware">'+tr("VMware")+'</option>\
</select><br />\
<label for="bridge">'+tr("Bridge")+':</label>\
<input type="text" name="bridge" id="bridge" /><br />\
<label for="phydev">'+tr("Physical device")+':</label>\
<input type="text" name="phydev" id="phydev" />\
<label for="vlan">'+tr("VLAN")+':</label>\
<select name="vlan" id="vlan">\
<option value="YES">'+tr("Yes")+'</option>\
<option value="NO">'+tr("No")+'</option>\
</select><br />\
<label for="vlan_id">'+tr("VLAN ID")+':</label>\
<input type="text" name="vlan_id" id="vlan_id" /><br />\
</fieldset>\
<fieldset>\
<label style="height:2em;">'+tr("Network type")+':</label>\
@ -530,12 +547,20 @@ function updateVNetworkInfo(request,vn){
<td class="key_td">'+tr("Group")+'</td>\
<td class="value_td">'+vn_info.GNAME+'</td>\
</tr>\
<tr>\
<td class="key_td">'+tr("Bridge")+'</td>\
<td class="value_td">'+ (typeof(vn_info.BRIDGE) == "object" ? "--": vn_info.BRIDGE) +'</td>\
</tr>\
<tr>\
<td class="key_td">'+tr("VLAN")+'</td>\
<td class="value_td">'+ (vn_info.VLAN == "0" ? "no" : "yes") +'</td>\
</tr>\
<tr>\
<td class="key_td">'+tr("Physical device")+'</td>\
<td class="value_td">'+ (typeof(vn_info.PHYDEV) == "object" ? "--": vn_info.PHYDEV) +'</td>\
</tr>\
<tr>\
<td class="key_td">'+tr("VNET ID")+'</td>\
<td class="key_td">'+tr("VLAN ID")+'</td>\
<td class="value_td">'+ (typeof(vn_info.VLAN_ID) == "object" ? "--": vn_info.VLAN_ID) +'</td>\
</tr>\
<tr><td class="key_td">Permissions</td><td></td></tr>\
@ -704,6 +729,36 @@ function setupCreateVNetDialog() {
$('div#fixed',$create_vn_dialog).hide();
$('div#ranged',$create_vn_dialog).show();
});
$('#network_mode',dialog).change(function(){
$('input,select#vlan,label[for!="network_mode"]', $(this).parent()).hide();
$('input', $(this).parent()).val("");
switch ($(this).val()) {
case "default":
$('input#bridge,label[for="bridge"]',$create_vn_dialog).show();
$('input#phydev,label[for="phydev"]',$create_vn_dialog).show();
break;
case "802.1Q":
$('input#bridge,label[for="bridge"]',$create_vn_dialog).show();
$('input#phydev,label[for="phydev"]',$create_vn_dialog).show();
$('select#vlan,label[for="vlan"]',$create_vn_dialog).show();
$('input#vlan_id,label[for="vlan_id"]',$create_vn_dialog).show();
break;
case "etables":
$('input#bridge,label[for="bridge"]',$create_vn_dialog).show();
break;
case "openvswitch":
case "vmware":
$('input#bridge,label[for="bridge"]',$create_vn_dialog).show();
$('select#vlan,label[for="vlan"]',$create_vn_dialog).show();
$('input#vlan_id,label[for="vlan_id"]',$create_vn_dialog).show();
break;
};
});
//Initialize shown options
$('#network_mode',dialog).trigger("change");
$('button',dialog).button();
@ -786,12 +841,60 @@ function setupCreateVNetDialog() {
notifyError(tr("Virtual Network name missing!"));
return false;
}
var bridge = $('#bridge',this).val();
var type = $('input:checked',this).val();
var network_json = {"name" : name};
var network_mode = $('select#network_mode',this).val();
var bridge = $('#bridge',this).val();
var phydev = $('#phydev',this).val();
var vlan = $('#vlan',this).val();
var vlan_id = $('#vlan_id',this).val();
switch (network_mode) {
case "default":
if (!bridge && !phydev){
notifyError("Bridge or physical device must be specified");
return false;
};
if (bridge) network_json['bridge']=bridge;
if (phydev) network_json['phydev']=phydev;
break;
case "802.1Q":
if (!phydev){
notifyError("Physical device must be specified");
return false;
};
network_json['phydev']=phydev;
if (bridge) network_json['bridge']=bridge;
if (vlan_id) {
network_json['vlan']=vlan;
network_json['vlan_id']=vlan_id;
};
break;
case "etables":
if (!bridge){
notifyError("Bridge must be specified");
return false;
};
network_json['bridge']=bridge;
break;
case "openvswitch":
case "vmware":
if (!bridge){
notifyError("Bridge must be specified");
return false;
};
network_json['bridge']=bridge;
if (vlan_id) {
network_json['vlan']=vlan;
network_json['vlan_id']=vlan_id;
};
break;
};
var type = $('input:checked',this).val();
network_json['type']=type;
//TODO: Name and bridge provided?!
var network_json = null;
if (type == "fixed") {
var leases = $('#leases option', this);
var leases_obj=[];
@ -807,12 +910,7 @@ function setupCreateVNetDialog() {
});
//and construct the final data for the request
network_json = {
"vnet" : {
"type" : "FIXED",
"leases" : leases_obj,
"bridge" : bridge,
"name" : name }};
network_json["leases"] = leases_obj;
}
else { //type ranged
@ -827,25 +925,17 @@ function setupCreateVNetDialog() {
return false;
};
//we form the object for the request
network_json = {
"vnet" : {
"type" : "RANGED",
"bridge" : bridge,
"name" : name }
};
if (network_addr.length)
network_json["vnet"]["network_address"]=network_addr;
network_json["network_address"]=network_addr;
if (network_mask.length)
network_json["vnet"]["network_mask"]=network_mask;
network_json["network_mask"]=network_mask;
if (custom){
if (ip_start.length)
network_json["vnet"]["ip_start"] = ip_start;
network_json["ip_start"] = ip_start;
if (ip_end.length)
network_json["vnet"]["ip_end"] = ip_end;
network_json["ip_end"] = ip_end;
};
};
@ -853,11 +943,13 @@ function setupCreateVNetDialog() {
$('#custom_var_vnet_box option',$create_vn_dialog).each(function(){
var attr_name = $(this).attr('name');
var attr_value = $(this).val();
network_json["vnet"][attr_name] = attr_value;
network_json[attr_name] = attr_value;
});
//Create the VNetwork.
network_json = {"vnet" : network_json};
Sunstone.runAction("Network.create",network_json);
$create_vn_dialog.dialog('close');
return false;

View File

@ -39,6 +39,7 @@ SUNSTONE_ROOT_DIR = File.dirname(__FILE__)
$: << RUBY_LIB_LOCATION
$: << RUBY_LIB_LOCATION+'/cloud'
$: << SUNSTONE_ROOT_DIR
$: << SUNSTONE_ROOT_DIR+'/models'
##############################################################################
@ -115,12 +116,28 @@ helpers do
session[:ip] = request.ip
session[:remember] = params[:remember]
#User IU options initialization
#Load options either from user settings or default config.
# - LANG
# - WSS CONECTION
if user['TEMPLATE/LANG']
session[:lang] = user['TEMPLATE/LANG']
else
session[:lang] = settings.config[:lang]
end
if user['TEMPLATE/VNC_WSS']
session[:wss] = user['TEMPLATE/VNC_WSS']
else
wss = settings.config[:vnc_proxy_support_wss]
#limit to yes,no options
session[:wss] = (wss == true || wss == "yes" || wss == "only" ?
"yes" : "no")
end
#end user options
if params[:remember]
env['rack.session.options'][:expire_after] = 30*60*60*24
end
@ -210,10 +227,18 @@ post '/logout' do
end
##############################################################################
# Config and Logs
# User configuration and VM logs
##############################################################################
get '/config' do
@SunstoneServer.get_configuration(session[:user_id])
uconf = {
:user_config => {
:lang => session[:lang],
:wss => session[:wss]
}
}
[200, uconf.to_json]
end
post '/config' do
@ -225,7 +250,8 @@ post '/config' do
body.each do | key,value |
case key
when "lang" then session[:lang]=value
when "lang" then session[:lang]= value
when "wss" then session[:wss] = value
end
end
end
@ -243,7 +269,8 @@ get '/:resource/monitor' do
nil,
params[:resource],
params[:monitor_resources],
session[:user_gid])
:uid => session[:user_id],
:gid => session[:user_gid])
end
get '/:resource/:id/monitor' do
@ -251,7 +278,8 @@ get '/:resource/:id/monitor' do
params[:id],
params[:resource],
params[:monitor_resources],
session[:user_gid])
:uid => session[:user_id],
:gid => session[:user_gid])
end
@ -282,6 +310,13 @@ delete '/:resource/:id' do
@SunstoneServer.delete_resource(params[:resource], params[:id])
end
##############################################################################
# Upload image
##############################################################################
post '/upload'do
@SunstoneServer.upload(params[:img], request.env['rack.input'].path)
end
##############################################################################
# Create a new Resource
##############################################################################
@ -301,7 +336,8 @@ post '/vm/:id/stopvnc' do
return [403, OpenNebula::Error.new(msg).to_json]
end
rc = @SunstoneServer.stopvnc(vm_id, vnc_hash[vm_id][:pipe])
rc = @SunstoneServer.stopvnc(vnc_hash[vm_id][:pipe])
if rc[0] == 200
session['vnc'].delete(vm_id)
end
@ -327,7 +363,8 @@ post '/vm/:id/startvnc' do
return [200, info.to_json]
end
rc = @SunstoneServer.startvnc(vm_id, settings.config)
rc = @SunstoneServer.startvnc(vm_id,settings.config)
if rc[0] == 200
info = rc[1]
session['vnc'][vm_id] = info.clone

View File

@ -17,6 +17,7 @@
<script type="text/javascript" src="vendor/jQueryLayout/jquery.layout-latest.min.js"></script>
<script type="text/javascript" src="vendor/dataTables/jquery.dataTables.min.js"></script>
<script language="javascript" type="text/javascript" src="vendor/flot/jquery.flot.min.js"></script>
<script type="text/javascript" src="vendor/fileuploader/fileuploader.js"></script>
<!-- End Vendor Libraries -->
@ -75,7 +76,7 @@
</div>
</div>
<div id="footer" class="ui-layout-south">
Copyright 2002-2012 &copy; OpenNebula Project Leads (<a href="http://opennebula.org" target="_blank">OpenNebula.org</a>). All Rights Reserved. OpenNebula 3.2.0
Copyright 2002-2012 &copy; OpenNebula Project Leads (<a href="http://opennebula.org" target="_blank">OpenNebula.org</a>). All Rights Reserved. OpenNebula 3.3.0
</div>

View File

@ -38,9 +38,9 @@ end
$: << RUBY_LIB_LOCATION
require 'pp'
require "VirtualMachineDriver"
require "CommandManager"
require 'scripts_common'
require "rexml/document"
# The main class for the EC2 driver
@ -48,27 +48,113 @@ class EC2Driver < VirtualMachineDriver
# EC2 commands constants
EC2 = {
:run => "#{EC2_LOCATION}/bin/ec2-run-instances",
:terminate => "#{EC2_LOCATION}/bin/ec2-terminate-instances",
:describe => "#{EC2_LOCATION}/bin/ec2-describe-instances",
:associate => "#{EC2_LOCATION}/bin/ec2-associate-address",
:reboot => "#{EC2_LOCATION}/bin/ec2-reboot-instances",
:authorize => "#{EC2_LOCATION}/bin/ec2-authorize"
:run => {
:cmd => "#{EC2_LOCATION}/bin/ec2-run-instances",
:args => {
"AKI" => {
:opt => '--kernel'
},
"AMI" => {
:opt => ''
},
"BLOCKDEVICEMAPPING" => {
:opt => '-b'
},
"CLIENTTOKEN" => {
:opt => '--client-token'
},
"INSTANCETYPE" => {
:opt => '-t'
},
"KEYPAIR" => {
:opt => '-k'
},
"LICENSEPOOL" => {
:opt => '--license-pool'
},
"PLACEMENTGROUP" => {
:opt => '--placement-group'
},
"PRIVATEIP" => {
:opt => '--private-ip-address'
},
"RAMDISK" => {
:opt => '--ramdisk'
},
"SUBNETID" => {
:opt => '-s'
},
"TENANCY" => {
:opt => '--tenancy'
},
"USERDATA" => {
:opt => '-d'
},
"USERDATAFILE" => {
:opt => '-f'
},
"SECURITYGROUPS" => {
:opt => '-g',
:proc => lambda {|str| str.split(',').join(' -g ')}
}
}
},
:terminate => {
:cmd => "#{EC2_LOCATION}/bin/ec2-terminate-instances"
},
:describe => {
:cmd => "#{EC2_LOCATION}/bin/ec2-describe-instances"
},
:associate => {
:cmd => "#{EC2_LOCATION}/bin/ec2-associate-address",
:args => {
"SUBNETID" => {
:opt => '-a',
:proc => lambda {|str| ''}
},
"ELASTICIP" => {
:opt => ''
}
}
},
:authorize => {
:cmd => "#{EC2_LOCATION}/bin/ec2-authorize",
:args => {
"AUTHORIZEDPORTS" => {
:opt => '-p',
:proc => lambda {|str| str.split(',').join(' -p ')}
}
}
},
:reboot => {
:cmd => "#{EC2_LOCATION}/bin/ec2-reboot-instances"
},
:stop => {
:cmd => "#{EC2_LOCATION}/bin/ec2-stop-instances"
},
:start => {
:cmd => "#{EC2_LOCATION}/bin/ec2-start-instances"
},
:tags => {
:cmd => "#{EC2_LOCATION}/bin/ec2-create-tags",
:args => {
"TAGS" => {
:opt => '-t',
:proc => lambda {|str| str.split(',').join(' -t ')}
}
}
}
}
# EC2 constructor, loads defaults for the EC2Driver
def initialize(ec2_conf = nil)
if !EC2_JVM_CONCURRENCY
concurrency = 5
else
concurrency = EC2_JVM_CONCURRENCY.to_i
end
super('',
:concurrency => concurrency,
:threaded => true
)
super('', :concurrency => concurrency, :threaded => true)
@defaults = Hash.new
@ -83,18 +169,127 @@ class EC2Driver < VirtualMachineDriver
return if !ec2
@defaults["KEYPAIR"] = ec2_value(ec2,"KEYPAIR")
@defaults["AUTHORIZEDPORTS"] = ec2_value(ec2,"AUTHORIZEDPORTS")
@defaults["INSTANCETYPE"] = ec2_value(ec2,"INSTANCETYPE")
EC2.each {|action, hash|
if hash[:args]
hash[:args].each { |key, value|
@defaults[key] = value_from_xml(ec2, key)
}
end
}
end
end
# DEPLOY action, also sets ports and ip if needed
def deploy(id, drv_message)
ec2_info = get_deployment_info(drv_message)
return unless ec2_info
if !ec2_value(ec2_info, 'AMI')
msg = "Can not find AMI in deployment file"
send_message(ACTION[:deploy], RESULT[:failure], id, msg)
return
end
deploy_exe = exec_and_log_ec2(:run, ec2_info, id)
if deploy_exe.code != 0
msg = deploy_exe.stderr
send_message(ACTION[:deploy], RESULT[:failure], id, msg)
return
end
if !deploy_exe.stdout.match(/^INSTANCE\s*(.+?)\s/)
msg = "Could not find instance id. Check ec2-describe-instances"
send_message(ACTION[:deploy], RESULT[:failure], id, msg)
return
end
deploy_id = $1
if ec2_value(ec2_info, 'AUTHORIZEDPORTS')
exec_and_log_ec2(:authorize, ec2_info, 'default', id)
end
if ec2_value(ec2_info, 'TAGS')
exec_and_log_ec2(:tags, ec2_info, deploy_id, id)
end
if ec2_value(ec2_info, 'ELASTICIP')
exec_and_log_ec2(:associate, ec2_info, "-i #{deploy_id}", id)
end
send_message(ACTION[:deploy], RESULT[:success], id, deploy_id)
end
# Shutdown a EC2 instance
def shutdown(id, drv_message)
ec2_action(drv_message, :terminate, ACTION[:shutdown], id)
end
# Reboot a EC2 instance
def reboot(id, drv_message)
ec2_action(drv_message, :reboot, ACTION[:reboot], id)
end
# Cancel a EC2 instance
def cancel(id, drv_message)
ec2_action(drv_message, :terminate, ACTION[:cancel], id)
end
# Stop a EC2 instance
def save(id, drv_message)
ec2_action(drv_message, :stop, ACTION[:save], id)
end
# Cancel a EC2 instance
def restore(id, drv_message)
ec2_action(drv_message, :start, ACTION[:restor], id)
end
# Get info (IP, and state) for a EC2 instance
def poll(id, drv_message)
msg = decode(drv_message)
deploy_id = msg.elements["DEPLOY_ID"].text
info = "#{POLL_ATTRIBUTE[:usedmemory]}=0 " \
"#{POLL_ATTRIBUTE[:usedcpu]}=0 " \
"#{POLL_ATTRIBUTE[:nettx]}=0 " \
"#{POLL_ATTRIBUTE[:netrx]}=0"
exe = exec_and_log_ec2(:describe, nil, deploy_id, id)
if exe.code != 0
send_message(ACTION[:poll], RESULT[:failure], id, exe.stderr)
return
end
exe.stdout.match(Regexp.new("INSTANCE\\s+#{deploy_id}\\s+(.+)"))
if !$1
info << " #{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:deleted]}"
else
monitor_data = $1.split(/\s+/)
case monitor_data[3]
when "pending"
info << " #{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:active]}"
when "running"
info<<" #{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:active]}"<<
" IP=#{monitor_data[1]}"
when "shutting-down","terminated"
info << " #{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:deleted]}"
end
end
send_message(ACTION[:poll], RESULT[:success], id, info)
end
private
def get_deployment_info(drv_message)
msg = decode(drv_message)
host = msg.elements["HOST"].text
local_dfile = msg.elements["LOCAL_DEPLOYMENT_FILE"].text
if !local_dfile
@ -134,150 +329,67 @@ class EC2Driver < VirtualMachineDriver
end
end
ami = ec2_value(ec2,"AMI")
keypair = ec2_value(ec2,"KEYPAIR")
eip = ec2_value(ec2,"ELASTICIP")
ports = ec2_value(ec2,"AUTHORIZEDPORTS")
type = ec2_value(ec2,"INSTANCETYPE")
if !ami
send_message(ACTION[:deploy],RESULT[:failure],id,
"Can not find AMI in deployment file #{local_dfile}")
return
end
deploy_cmd = "#{EC2[:run]} #{ami}"
deploy_cmd << " -k #{keypair}" if keypair
deploy_cmd << " -t #{type}" if type
deploy_exe = LocalCommand.run(deploy_cmd, log_method(id))
if deploy_exe.code != 0
send_message(ACTION[:deploy],RESULT[:failure],id)
return
end
if !deploy_exe.stdout.match(/^INSTANCE\s*(.+?)\s/)
send_message(ACTION[:deploy],RESULT[:failure],id,
"Could not find instance id. Check ec2-describe-instances")
return
end
deploy_id = $1
if eip
ip_cmd = "#{EC2[:associate]} #{eip} -i #{deploy_id}"
ip_exe = LocalCommand.run(ip_cmd, log_method(id))
end
if ports
ports_cmd = "#{EC2[:authorize]} default -p #{ports}"
ports_exe = LocalCommand.run(ports_cmd, log_method(id))
end
send_message(ACTION[:deploy],RESULT[:success],id,deploy_id)
ec2
end
# Shutdown a EC2 instance
def shutdown(id, drv_message)
# Execute an EC2 command and send the SUCCESS or FAILURE signal
# +drv_message+: String, base64 encoded info sent by ONE
# +ec2_action+: Symbol, one of the keys of the EC2 hash constant (i.e :run)
# +one_action+: String, OpenNebula action
# +id+: String, action id
def ec2_action(drv_message, ec2_action, one_action, id)
msg = decode(drv_message)
host = msg.elements["HOST"].text
deploy_id = msg.elements["DEPLOY_ID"].text
ec2_terminate(ACTION[:shutdown], id, deploy_id)
end
# Reboot a EC2 instance
def reboot(id, drv_message)
cmd = "#{EC2_LOCATION}/bin/ec2-reboot-instances #{deploy_id}"
exe = LocalCommand.run(cmd, log_method(id))
exe = exec_and_log_ec2(ec2_action, nil, deploy_id, id)
if exe.code != 0
result = RESULT[:failure]
send_message(one_action, RESULT[:failure], id, exe.stderr)
else
result = RESULT[:success]
send_message(one_action, RESULT[:success], id)
end
send_message(action,result,id)
end
# Cancel a EC2 instance
def cancel(id, drv_message)
msg = decode(drv_message)
# Execute an EC2 command and log the message if error
# This function will build the command joining the :cmd value of the EC2
# hash, the extra_params string and the options built from the :args schema
# of the EC2 hash and the xml
# +action+: Symbol, one of the keys of the EC2 hash constant (i.e :run)
# +xml+: REXML Document, containing EC2 information
# +extra_params+: String, extra information to be added to the command
def exec_and_log_ec2(action, xml, extra_params="", id)
cmd = EC2[action][:cmd].clone
cmd << ' ' << extra_params << ' ' if extra_params
host = msg.elements["HOST"].text
deploy_id = msg.elements["DEPLOY_ID"].text
ec2_terminate(ACTION[:cancel], id, deploy_id)
end
# Get info (IP, and state) for a EC2 instance
def poll(id, drv_message)
msg = decode(drv_message)
host = msg.elements["HOST"].text
deploy_id = msg.elements["DEPLOY_ID"].text
info = "#{POLL_ATTRIBUTE[:usedmemory]}=0 " \
"#{POLL_ATTRIBUTE[:usedcpu]}=0 " \
"#{POLL_ATTRIBUTE[:nettx]}=0 " \
"#{POLL_ATTRIBUTE[:netrx]}=0"
cmd = "#{EC2[:describe]} #{deploy_id}"
exe = LocalCommand.run(cmd, log_method(id))
if exe.code != 0
send_message(ACTION[:poll],RESULT[:failure],id)
return
if EC2[action][:args]
cmd << EC2[action][:args].map {|k,v|
str = ec2_value(xml, k, &v[:proc])
v[:opt] + ' ' + str if str
}.join(' ')
end
exe.stdout.match(Regexp.new("INSTANCE\\s+#{deploy_id}\\s+(.+)"))
LocalCommand.run(cmd, log_method(id))
end
if !$1
info << " #{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:deleted]}"
# Returns the value of the xml specified by the name or the default
# one if it does not exist
# +xml+: REXML Document, containing EC2 information
# +name+: String, xpath expression to retrieve the value
# +block+: Block, block to be applied to the value before returning it
def ec2_value(xml, name, &block)
value = value_from_xml(xml, name) || @defaults[name]
if block_given? && value
block.call(value)
else
monitor_data = $1.split(/\s+/)
case monitor_data[3]
when "pending"
info << " #{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:active]}"
when "running"
info<<" #{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:active]}"<<
" IP=#{monitor_data[1]}"
when "shutting-down","terminated"
info << " #{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:deleted]}"
end
value
end
send_message(ACTION[:poll], RESULT[:success], id, info)
end
private
def ec2_terminate(action, id, deploy_id)
cmd = "#{EC2_LOCATION}/bin/ec2-terminate-instances #{deploy_id}"
exe = LocalCommand.run(cmd, log_method(id))
if exe.code != 0
result = RESULT[:failure]
else
result = RESULT[:success]
def value_from_xml(xml, name)
if xml
element = xml.elements[name]
element.text.strip if element && element.text
end
send_message(action,result,id)
end
def ec2_value(xml,name)
value = nil
element = xml.elements[name]
value = element.text.strip if element && element.text
if !value
value = @defaults[name]
end
return value
end
end

View File

@ -108,8 +108,6 @@ int VirtualNetworkPool::allocate (
goto error_duplicated;
}
vn = new VirtualNetwork(uid, gid, uname, gname, vn_template);
*oid = PoolSQL::allocate(vn, error_str);
return *oid;