ruby-opennebula-4.4 - initial gem2deb package.
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Wed, 12 Mar 2014 17:31:58 +0000 (18:31 +0100)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Wed, 12 Mar 2014 17:31:58 +0000 (18:31 +0100)
52 files changed:
ruby-opennebula-4.4/LICENSE [new file with mode: 0644]
ruby-opennebula-4.4/NOTICE [new file with mode: 0644]
ruby-opennebula-4.4/checksums.yaml.gz [new file with mode: 0644]
ruby-opennebula-4.4/debian/changelog [new file with mode: 0644]
ruby-opennebula-4.4/debian/compat [new file with mode: 0644]
ruby-opennebula-4.4/debian/control [new file with mode: 0644]
ruby-opennebula-4.4/debian/copyright [new file with mode: 0644]
ruby-opennebula-4.4/debian/ruby-opennebula.docs [new file with mode: 0644]
ruby-opennebula-4.4/debian/rules [new file with mode: 0755]
ruby-opennebula-4.4/debian/source/format [new file with mode: 0644]
ruby-opennebula-4.4/debian/watch [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/acl.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/acl_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/client.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/cluster.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/cluster_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/datastore.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/datastore_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/document.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/document_json.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/document_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/document_pool_json.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/error.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/group.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/group_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/host.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/host_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/image.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/image_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/ldap_auth.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/ldap_auth_spec.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/oneflow_client.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/pool_element.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/server_cipher_auth.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/server_x509_auth.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/ssh_auth.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/system.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/template.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/template_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/user.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/user_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/virtual_machine.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/virtual_machine_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/virtual_network.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/virtual_network_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/x509_auth.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/xml_element.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/xml_pool.rb [new file with mode: 0644]
ruby-opennebula-4.4/lib/opennebula/xml_utils.rb [new file with mode: 0644]
ruby-opennebula-4.4/metadata.yml [new file with mode: 0644]

diff --git a/ruby-opennebula-4.4/LICENSE b/ruby-opennebula-4.4/LICENSE
new file mode 100644 (file)
index 0000000..d645695
--- /dev/null
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/ruby-opennebula-4.4/NOTICE b/ruby-opennebula-4.4/NOTICE
new file mode 100644 (file)
index 0000000..0e12ebb
--- /dev/null
@@ -0,0 +1,51 @@
+OpenNebula Open Source Project
+--------------------------------------------------------------------------------
+Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs
+--------------------------------------------------------------------------------
+
+You can find  more information about the project, release notes and
+documentation at www.OpenNebula.org
+
+AUTHORS
+
+- Ruben Santiago Montero (rsmontero@opennebula.org)
+- Ignacio Martin Llorente (imllorente@opennebula.org)
+
+ACKNOWLEDGEMENTS
+
+The following people have contributed to the development of the technology
+- Javier Fontan Muiños (jfontan@opennebula.org)
+- Constantino Vazquez Blanco (tinova@opennebula.org)
+- Jaime Melis Bayo (jmelis@opennebula.org)
+- Carlos Martin Sanchez (cmartin@opennebula.org)
+- Daniel Molina Aranda (dmolina@opennebula.org)
+- Hector Sanjuan Redondo (hsanjuan@opennebula.org)
+
+The new features for service elasticity (oneFlow) introduced in OpenNebula 4.2
+were funded by BlackBerry in the context of the Fund a Feature Program.
+
+OpenNebula Project also acknowledges the contributions of C12G Labs developers.
+
+LICENSE
+
+OpenNebula is licensed under the Apache License, Version 2.0 (the
+"License"); you may not use this software 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 Apache License.
+
+THIRD-PARTY SOFTWARE
+
+OpenNebula distribution includes third-party software under fully compatible
+open-source licenses. See the following directories and the NOTICE files
+they contain for more information:
+
+- share/vendor
+- src/sunstone/public/vendor
+- src/oca/java/lib
diff --git a/ruby-opennebula-4.4/checksums.yaml.gz b/ruby-opennebula-4.4/checksums.yaml.gz
new file mode 100644 (file)
index 0000000..18c22a4
Binary files /dev/null and b/ruby-opennebula-4.4/checksums.yaml.gz differ
diff --git a/ruby-opennebula-4.4/debian/changelog b/ruby-opennebula-4.4/debian/changelog
new file mode 100644 (file)
index 0000000..38966ec
--- /dev/null
@@ -0,0 +1,5 @@
+ruby-opennebula (4.4.0-1) UNRELEASED; urgency=medium
+
+  * Initial release (Closes: #nnnn)
+
+ -- František Dvořák <valtri@civ.zcu.cz>  Wed, 12 Mar 2014 18:30:49 +0100
diff --git a/ruby-opennebula-4.4/debian/compat b/ruby-opennebula-4.4/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/ruby-opennebula-4.4/debian/control b/ruby-opennebula-4.4/debian/control
new file mode 100644 (file)
index 0000000..8b93418
--- /dev/null
@@ -0,0 +1,19 @@
+Source: ruby-opennebula
+Section: ruby
+Priority: optional
+Maintainer: Debian Ruby Extras Maintainers <pkg-ruby-extras-maintainers@lists.alioth.debian.org>
+Uploaders: František Dvořák <valtri@civ.zcu.cz>
+Build-Depends: debhelper (>= 7.0.50~), gem2deb (>= 0.6.1~)
+Standards-Version: 3.9.4
+#Vcs-Git: git://anonscm.debian.org/pkg-ruby-extras/ruby-opennebula.git
+#Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-ruby-extras/ruby-opennebula.git;a=summary
+Homepage: http://opennebula.org
+XS-Ruby-Versions: all
+
+Package: ruby-opennebula
+Architecture: all
+XB-Ruby-Versions: ${ruby:Versions}
+Depends: ${shlibs:Depends}, ${misc:Depends}, ruby | ruby-interpreter
+# nokogiri (>= 0), json (>= 0)
+Description: OpenNebula Client API
+ Libraries needed to talk to OpenNebula
diff --git a/ruby-opennebula-4.4/debian/copyright b/ruby-opennebula-4.4/debian/copyright
new file mode 100644 (file)
index 0000000..1c1e1f6
--- /dev/null
@@ -0,0 +1,35 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: opennebula
+Source: FIXME <http://example.com/>
+
+Files: *
+Copyright: <years> <put author's name and email here>
+           <years> <likewise for another author>
+License: GPL-2+ (FIXME)
+
+Files: debian/*
+Copyright: 2014 František Dvořák <valtri@civ.zcu.cz>
+License: GPL-2+ (FIXME)
+Comment: the Debian packaging is licensed under the same terms as the original package.
+
+License: GPL-2+ (FIXME)
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ .
+ This program is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.  See the GNU General Public License for more
+ details.
+ .
+ You should have received a copy of the GNU General Public
+ License along with this package; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2'.
diff --git a/ruby-opennebula-4.4/debian/ruby-opennebula.docs b/ruby-opennebula-4.4/debian/ruby-opennebula.docs
new file mode 100644 (file)
index 0000000..d0ab95f
--- /dev/null
@@ -0,0 +1 @@
+# FIXME: READMEs found
diff --git a/ruby-opennebula-4.4/debian/rules b/ruby-opennebula-4.4/debian/rules
new file mode 100755 (executable)
index 0000000..82ddc0c
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/make -f
+#export DH_VERBOSE=1
+#
+# Uncomment to ignore all test failures (but the tests will run anyway)
+#export DH_RUBY_IGNORE_TESTS=all
+#
+# Uncomment to ignore some test failures (but the tests will run anyway).
+# Valid values:
+#export DH_RUBY_IGNORE_TESTS=ruby1.9.1 ruby2.0 require-rubygems
+#
+# If you need to specify the .gemspec (eg there is more than one)
+#export DH_RUBY_GEMSPEC=gem.gemspec
+
+%:
+       dh $@ --buildsystem=ruby --with ruby
diff --git a/ruby-opennebula-4.4/debian/source/format b/ruby-opennebula-4.4/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/ruby-opennebula-4.4/debian/watch b/ruby-opennebula-4.4/debian/watch
new file mode 100644 (file)
index 0000000..5d5095f
--- /dev/null
@@ -0,0 +1,2 @@
+version=3
+http://pkg-ruby-extras.alioth.debian.org/cgi-bin/gemwatch/opennebula .*/opennebula-(.*).tar.gz
diff --git a/ruby-opennebula-4.4/lib/opennebula.rb b/ruby-opennebula-4.4/lib/opennebula.rb
new file mode 100644 (file)
index 0000000..13e5b5b
--- /dev/null
@@ -0,0 +1,58 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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.                                             #
+#--------------------------------------------------------------------------- #
+
+
+begin # require 'rubygems'
+    require 'rubygems'
+rescue Exception
+end
+
+require 'digest/sha1'
+require 'rexml/document'
+require 'pp'
+
+require 'opennebula/xml_utils'
+require 'opennebula/client'
+require 'opennebula/error'
+require 'opennebula/virtual_machine'
+require 'opennebula/virtual_machine_pool'
+require 'opennebula/virtual_network'
+require 'opennebula/virtual_network_pool'
+require 'opennebula/image'
+require 'opennebula/image_pool'
+require 'opennebula/user'
+require 'opennebula/user_pool'
+require 'opennebula/host'
+require 'opennebula/host_pool'
+require 'opennebula/template'
+require 'opennebula/template_pool'
+require 'opennebula/group'
+require 'opennebula/group_pool'
+require 'opennebula/acl'
+require 'opennebula/acl_pool'
+require 'opennebula/datastore'
+require 'opennebula/datastore_pool'
+require 'opennebula/cluster'
+require 'opennebula/cluster_pool'
+require 'opennebula/document'
+require 'opennebula/document_pool'
+require 'opennebula/system'
+
+module OpenNebula
+
+    # OpenNebula version
+    VERSION = '4.4.0'
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/acl.rb b/ruby-opennebula-4.4/lib/opennebula/acl.rb
new file mode 100644 (file)
index 0000000..1051d0e
--- /dev/null
@@ -0,0 +1,265 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 OpenNebula
+
+    # Abstract rules of the type USER RESOURCE RIGHTS
+    # which are:
+    #     USER      -> #<num>
+    #                  @<num>
+    #                  ALL
+    #     RESOURCE  -> + separated list and "/{#,@,%}<num>|ALL"
+    #                  VM,
+    #                  HOST
+    #                  NET
+    #                  IMAGE
+    #                  USER
+    #                  TEMPLATE
+    #                  GROUP
+    #                  ACL
+    #     RIGHTS    -> + separated list
+    #                  USE
+    #                  MANAGE
+    #                  ADMIN
+    #                  CREATE
+    class Acl < PoolElement
+
+        USERS = {
+            "UID"           => 0x100000000,
+            "GID"           => 0x200000000,
+            "ALL"           => 0x400000000,
+            "CLUSTER"       => 0x800000000
+        }
+
+        RESOURCES =
+        {
+            "VM"            => 0x1000000000,
+            "HOST"          => 0x2000000000,
+            "NET"           => 0x4000000000,
+            "IMAGE"         => 0x8000000000,
+            "USER"          => 0x10000000000,
+            "TEMPLATE"      => 0x20000000000,
+            "GROUP"         => 0x40000000000,
+            "DATASTORE"     => 0x100000000000,
+            "CLUSTER"       => 0x200000000000,
+            "DOCUMENT"      => 0x400000000000
+        }
+
+        RIGHTS =
+        {
+            "USE"           => 0x1,  # Auth. to use an object
+            "MANAGE"        => 0x2,  # Auth. to perform management actions
+            "ADMIN"         => 0x4,  # Auth. to perform administrative actions
+            "CREATE"        => 0x8   # Auth. to create an object
+        }
+
+        # Constructor
+        #
+        # @param xml [String] must be an xml built with {.build_xml}
+        # @param client [Client] represents an XML-RPC connection
+        def initialize(xml, client)
+            super(xml,client)
+        end
+
+        # Creates an empty XML representation. It contains the id, if it is
+        # specified.
+        #
+        # @param pe_id [Integer] rule ID
+        #
+        # @return [String] an empty XML representation
+        def self.build_xml(pe_id=nil)
+            if pe_id
+                acl_xml = "<ACL><ID>#{pe_id}</ID></ACL>"
+            else
+                acl_xml = "<ACL></ACL>"
+            end
+
+            XMLElement.build_xml(acl_xml,'ACL')
+        end
+
+        # Creates a new ACL rule.
+        #
+        # @param user [String]
+        #   A string containing a hex number, e.g. 0x100000001
+        # @param resource [String]
+        #   A string containing a hex number, e.g. 0x2100000001
+        # @param rights [String]
+        #   A string containing a hex number, e.g. 0x10
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def allocate(user, resource, rights)
+            return super( AclPool::ACL_POOL_METHODS[:addrule],
+                          user,
+                          resource,
+                          rights )
+        end
+
+        # Deletes the Acl rule
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def delete()
+            super(AclPool::ACL_POOL_METHODS[:delrule])
+        end
+
+        # Does nothing, individual ACL rules info can't be retrieved from
+        # OpenNebula
+        #
+        # @return [nil] nil
+        def info()
+            return nil
+        end
+
+        alias_method :info!, :info
+
+        # Parses a rule string, e.g. "#5 HOST+VM/@12 INFO+CREATE+DELETE"
+        #
+        # @param rule_str [String] an ACL rule in string format
+        #
+        # @return [Array] an Array containing 3 strings (hex 64b numbers),
+        # or OpenNebula::Error objects
+        def self.parse_rule(rule_str)
+            ret = Array.new
+
+            rule_str = rule_str.split(" ")
+
+            if rule_str.length != 3
+                return OpenNebula::Error.new(
+                    "String needs three components: User, Resource, Rights")
+            end
+
+            ret << parse_users(rule_str[0])
+            ret << parse_resources(rule_str[1])
+            ret << parse_rights(rule_str[2])
+
+            errors=ret.map do |arg|
+                if OpenNebula.is_error?(arg)
+                    arg.message
+                else
+                    nil
+                end
+            end
+
+            errors.compact!
+
+            if errors.length>0
+                return OpenNebula::Error.new(errors.join(', '))
+            end
+
+            return ret
+        end
+
+private
+
+        # Converts a string in the form [#<id>, @<id>, *] to a hex. number
+        #
+        # @param users [String] Users component string
+        #
+        # @return [String] A string containing a hex number
+        def self.parse_users(users)
+           begin
+               return calculate_ids(users).to_i.to_s(16)
+           rescue Exception  => e
+               return OpenNebula::Error.new(e.message)
+           end
+        end
+
+        # Converts a resources string to a hex. number
+        #
+        # @param resources [String] Resources component string
+        #
+        # @return [String] A string containing a hex number
+        def self.parse_resources(resources)
+            begin
+                ret = 0
+                resources = resources.split("/")
+
+                if resources.size != 2
+                    raise "Resource '#{resources}' malformed"
+                end
+
+                resources[0].split("+").each{ |resource|
+                    if !RESOURCES[resource.upcase]
+                        raise "Resource '#{resource}' does not exist"
+                    end
+                    ret += RESOURCES[resource.upcase]
+                }
+
+                ret += calculate_ids(resources[1])
+
+                return ret.to_i.to_s(16)
+            rescue Exception  => e
+                return OpenNebula::Error.new(e.message)
+            end
+        end
+
+        # Converts a rights string to a hex. number
+        #
+        # @param rights [String] Rights component string
+        #
+        # @return [String] A string containing a hex number
+        def self.parse_rights(rights)
+            begin
+                ret = 0
+                rights = rights.split("+")
+
+                rights.each{ |right|
+                    raise "Right '#{right}' does not exist" if !RIGHTS[right.upcase]
+
+                    ret += RIGHTS[right.upcase]
+                }
+
+                return ret.to_i.to_s(16)
+            rescue Exception  => e
+                return OpenNebula::Error.new(e.message)
+            end
+        end
+
+        # Calculates the numeric value for a String containing an individual
+        # (#<id>), group (@<id>) or all (*) ID component
+        #
+        # @param id_str [String] Rule Id string
+        #
+        # @return [Integer] the numeric value for the given id_str
+        def self.calculate_ids(id_str)
+            raise "ID string '#{id_str}' malformed" if
+                !id_str.match(/^([\#@\%]\d+|\*)$/)
+
+            value = 0
+
+            case id_str[0..0]
+                when "#"
+                    value = USERS["UID"]
+                    users_value = id_str[1..-1].to_i + value
+
+                when "@"
+                    value = USERS["GID"]
+                    users_value = id_str[1..-1].to_i + value
+
+                when "*"
+                    users_value = USERS["ALL"]
+
+                when "%"
+                    value = USERS["CLUSTER"]
+                    users_value = id_str[1..-1].to_i + value
+            end
+
+            return users_value
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/acl_pool.rb b/ruby-opennebula-4.4/lib/opennebula/acl_pool.rb
new file mode 100644 (file)
index 0000000..02e4263
--- /dev/null
@@ -0,0 +1,55 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class AclPool < Pool
+
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+
+        ACL_POOL_METHODS = {
+            :info       => "acl.info",
+            :addrule    => "acl.addrule",
+            :delrule    => "acl.delrule"
+        }
+
+        # Class constructor
+        def initialize(client)
+            super('ACL_POOL','ACL',client)
+        end
+
+        def factory(element_xml)
+            OpenNebula::Acl.new(element_xml, @client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods
+        #######################################################################
+
+        # Retrieves the ACL Pool
+        def info()
+        # Retrieves all the Acls in the pool.
+            super(ACL_POOL_METHODS[:info])
+        end
+
+        alias_method :info!, :info
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/client.rb b/ruby-opennebula-4.4/lib/opennebula/client.rb
new file mode 100644 (file)
index 0000000..2e7d658
--- /dev/null
@@ -0,0 +1,119 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'xmlrpc/client'
+
+module OpenNebula
+    if OpenNebula::NOKOGIRI
+        class NokogiriStreamParser < XMLRPC::XMLParser::AbstractStreamParser
+            def initialize
+                @parser_class = NokogiriParser
+            end
+
+            class NokogiriParser < Nokogiri::XML::SAX::Document
+                include XMLRPC::XMLParser::StreamParserMixin
+
+                alias :cdata_block :character
+                alias :characters :character
+                alias :end_element :endElement
+                alias :start_element :startElement
+
+                def parse(str)
+                    parser = Nokogiri::XML::SAX::Parser.new(self)
+                    parser.parse(str)
+                end
+            end
+        end
+    end
+
+    # The client class, represents the connection with the core and handles the
+    # xml-rpc calls.
+    class Client
+        attr_accessor :one_auth
+
+        begin
+            require 'xmlparser'
+            XMLPARSER=true
+        rescue LoadError
+            XMLPARSER=false
+        end
+
+        # Creates a new client object that will be used to call OpenNebula
+        # functions.
+        #
+        # @param [String, nil] secret user credentials ("user:password") or
+        #   nil to get the credentials from user auth file
+        # @param [String, nil] endpoint OpenNebula server endpoint
+        #   (http://host:2633/RPC2) or nil to get it form the environment
+        #   variable ONE_XMLRPC or use the default endpoint
+        # @param [Hash] options
+        # @option params [Integer] :timeout connection timeout in seconds,
+        #   defaults to 30
+        #
+        # @return [OpenNebula::Client]
+        def initialize(secret=nil, endpoint=nil, options={})
+            if secret
+                @one_auth = secret
+            elsif ENV["ONE_AUTH"] and !ENV["ONE_AUTH"].empty? and
+                    File.file?(ENV["ONE_AUTH"])
+                @one_auth = File.read(ENV["ONE_AUTH"])
+            elsif File.file?(ENV["HOME"]+"/.one/one_auth")
+                @one_auth = File.read(ENV["HOME"]+"/.one/one_auth")
+            else
+                raise "ONE_AUTH file not present"
+            end
+
+            @one_auth.rstrip!
+
+            if endpoint
+                @one_endpoint = endpoint
+            elsif ENV["ONE_XMLRPC"]
+                @one_endpoint = ENV["ONE_XMLRPC"]
+            else
+                @one_endpoint = "http://localhost:2633/RPC2"
+            end
+
+            timeout=nil
+            timeout=options[:timeout] if options[:timeout]
+
+            @server = XMLRPC::Client.new2(@one_endpoint, nil, timeout)
+
+            if OpenNebula::NOKOGIRI
+                @server.set_parser(NokogiriStreamParser.new)
+            elsif XMLPARSER
+                @server.set_parser(XMLRPC::XMLParser::XMLStreamParser.new)
+            end
+        end
+
+        def call(action, *args)
+            begin
+                response = @server.call_async("one."+action, @one_auth, *args)
+
+                if response[0] == false
+                    Error.new(response[1], response[2])
+                else
+                    response[1] #response[1..-1]
+                end
+            rescue Exception => e
+                Error.new(e.message)
+            end
+        end
+
+        def get_version()
+            call("system.version")
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/cluster.rb b/ruby-opennebula-4.4/lib/opennebula/cluster.rb
new file mode 100644 (file)
index 0000000..25c9d75
--- /dev/null
@@ -0,0 +1,262 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+
+module OpenNebula
+    class Cluster < PoolElement
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+        CLUSTER_METHODS = {
+            :info           => "cluster.info",
+            :allocate       => "cluster.allocate",
+            :delete         => "cluster.delete",
+            :addhost        => "cluster.addhost",
+            :delhost        => "cluster.delhost",
+            :adddatastore   => "cluster.adddatastore",
+            :deldatastore   => "cluster.deldatastore",
+            :addvnet        => "cluster.addvnet",
+            :delvnet        => "cluster.delvnet",
+            :update         => "cluster.update",
+            :rename         => "cluster.rename"
+        }
+
+        # Creates a Cluster description with just its identifier
+        # this method should be used to create plain Cluster objects.
+        # +id+ the id of the host
+        #
+        # Example:
+        #   cluster = Cluster.new(Cluster.build_xml(3),rpc_client)
+        #
+        def Cluster.build_xml(pe_id=nil)
+            if pe_id
+                cluster_xml = "<CLUSTER><ID>#{pe_id}</ID></CLUSTER>"
+            else
+                cluster_xml = "<CLUSTER></CLUSTER>"
+            end
+
+            XMLElement.build_xml(cluster_xml,'CLUSTER')
+        end
+
+        # Class constructor
+        def initialize(xml, client)
+            super(xml,client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Cluster Object
+        #######################################################################
+
+        # Retrieves the information of the given Cluster.
+        def info()
+            super(CLUSTER_METHODS[:info], 'CLUSTER')
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new Cluster in OpenNebula
+        #
+        # +clustername+ A string containing the name of the Cluster.
+        def allocate(clustername)
+            super(CLUSTER_METHODS[:allocate], clustername)
+        end
+
+        # Deletes the Cluster
+        def delete()
+            super(CLUSTER_METHODS[:delete])
+        end
+
+        # Adds a Host to this Cluster
+        # @param hid [Integer] Host ID
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def addhost(hid)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(CLUSTER_METHODS[:addhost], @pe_id, hid)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Deletes a Host from this Cluster
+        # @param hid [Integer] Host ID
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def delhost(hid)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(CLUSTER_METHODS[:delhost], @pe_id, hid)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Adds a Datastore to this Cluster
+        # @param ds_id [Integer] Datastore ID
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def adddatastore(ds_id)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(CLUSTER_METHODS[:adddatastore], @pe_id, ds_id)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Deletes a Datastore from this Cluster
+        # @param ds_id [Integer] Datastore ID
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def deldatastore(ds_id)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(CLUSTER_METHODS[:deldatastore], @pe_id, ds_id)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Adds a VNet to this Cluster
+        # @param vnet_id [Integer] VNet ID
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def addvnet(vnet_id)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(CLUSTER_METHODS[:addvnet], @pe_id, vnet_id)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Deletes a VNet from this Cluster
+        # @param vnet_id [Integer] VNet ID
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def delvnet(vnet_id)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(CLUSTER_METHODS[:delvnet], @pe_id, vnet_id)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Replaces the template contents
+        #
+        # @param new_template [String] New template contents
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(new_template, append=false)
+            super(CLUSTER_METHODS[:update], new_template, append ? 1 : 0)
+        end
+
+        # Renames this Cluster
+        #
+        # @param name [String] New name for the Cluster.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def rename(name)
+            return call(CLUSTER_METHODS[:rename], @pe_id, name)
+        end
+
+        # ---------------------------------------------------------------------
+        # Helpers to get information
+        # ---------------------------------------------------------------------
+
+        # Returns whether or not the host with 'id' is part of this cluster
+        # @param id [Integer|Array] host ID
+        # @return [Boolean] true if found 
+        def contains_host?(id)
+            contains_resource?('HOSTS/ID', id)
+        end
+
+        # Returns an array with the numeric host ids
+        # @return [Array<Integer>]
+        def host_ids
+            array = Array.new
+
+            self.each("HOSTS/ID") do |id|
+                array << id.text.to_i
+            end
+
+            return array
+        end
+
+        # Returns whether or not the datastore with 'id' is part of this cluster
+        # @param id [Integer|Array] datastore ID
+        # @return [Boolean] true if found 
+        def contains_datastore?(id)
+            contains_resource?('DATASTORES/ID', id)
+        end
+
+        # Returns an array with the numeric datastore ids
+        # @return [Array<Integer>]
+        def datastore_ids
+            array = Array.new
+
+            self.each("DATASTORES/ID") do |id|
+                array << id.text.to_i
+            end
+
+            return array
+        end
+
+        # Returns whether or not the vnet with 'id' is part of this cluster
+        # @param id [Integer|Arrray] vnet ID
+        # @return [Boolean] true if found 
+        def contains_vnet?(id)
+            contains_resource?('VNETS/ID', id)
+        end
+
+        # Returns an array with the numeric vnet ids
+        # @return [Array<Integer>]
+        def vnet_ids
+            array = Array.new
+
+            self.each("VNETS/ID") do |id|
+                array << id.text.to_i
+            end
+
+            return array
+        end
+
+        private
+
+        def contains_resource?(xpath, id)
+            id_array = retrieve_elements(xpath)
+
+            return false if id_array.nil?
+
+            id = [id] if id.class != Array
+
+            id.each { |i| 
+                return false if !id_array.include?(i.to_s)
+            }
+
+            return true
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/cluster_pool.rb b/ruby-opennebula-4.4/lib/opennebula/cluster_pool.rb
new file mode 100644 (file)
index 0000000..6cf024d
--- /dev/null
@@ -0,0 +1,58 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class ClusterPool < Pool
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+        NONE_CLUSTER_ID      = -1
+        DEFAULT_CLUSTER_ID   = 0
+
+        CLUSTER_POOL_METHODS = {
+            :info => "clusterpool.info"
+        }
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+        # +client+ a Client object that represents a XML-RPC connection
+        def initialize(client)
+            super('CLUSTER_POOL','CLUSTER',client)
+        end
+
+        # Factory method to create Cluster objects
+        def factory(element_xml)
+            OpenNebula::Cluster.new(element_xml,@client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Cluster Object
+        #######################################################################
+
+        # Retrieves all the Clusters in the pool.
+        def info()
+            super(CLUSTER_POOL_METHODS[:info])
+        end
+
+        alias_method :info!, :info
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/datastore.rb b/ruby-opennebula-4.4/lib/opennebula/datastore.rb
new file mode 100644 (file)
index 0000000..fe702ab
--- /dev/null
@@ -0,0 +1,184 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+
+module OpenNebula
+    class Datastore < PoolElement
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+        DATASTORE_METHODS = {
+            :info       => "datastore.info",
+            :allocate   => "datastore.allocate",
+            :delete     => "datastore.delete",
+            :update     => "datastore.update",
+            :chown      => "datastore.chown",
+            :chmod      => "datastore.chmod",
+            :rename     => "datastore.rename"
+        }
+
+        DATASTORE_TYPES=%w{IMAGE SYSTEM FILE}
+
+        SHORT_DATASTORE_TYPES = {
+            "IMAGE" => "img",
+            "SYSTEM"=> "sys",
+            "FILE"  => "fil"
+        }
+
+        # Creates a Datastore description with just its identifier
+        # this method should be used to create plain Datastore objects.
+        # +id+ the id of the user
+        #
+        # Example:
+        #   datastore = Datastore.new(Datastore.build_xml(3),rpc_client)
+        #
+        def Datastore.build_xml(pe_id=nil)
+            if pe_id
+                datastore_xml = "<DATASTORE><ID>#{pe_id}</ID></DATASTORE>"
+            else
+                datastore_xml = "<DATASTORE></DATASTORE>"
+            end
+
+            XMLElement.build_xml(datastore_xml,'DATASTORE')
+        end
+
+        # Class constructor
+        def initialize(xml, client)
+            super(xml,client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Datastore Object
+        #######################################################################
+        # Returns the datastore type
+        def type
+            self['TYPE'].to_i
+        end
+
+        # Returns the datastore type (string value)
+        def type_str
+            DATASTORE_TYPES[type]
+        end
+
+        # Returns the datastore type (string value)
+        def short_type_str
+            SHORT_DATASTORE_TYPES[type_str]
+        end
+
+        # Retrieves the information of the given Datastore.
+        def info()
+            super(DATASTORE_METHODS[:info], 'DATASTORE')
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new Datastore in OpenNebula
+        #
+        # @param description [String] The template of the Datastore.
+        # @param cluster_id [Integer] Id of the cluster
+        #
+        # @return [Integer, OpenNebula::Error] the new ID in case of
+        #   success, error otherwise
+        def allocate(description, cluster_id=ClusterPool::NONE_CLUSTER_ID)
+            super(DATASTORE_METHODS[:allocate], description, cluster_id)
+        end
+
+        # Deletes the Datastore
+        def delete()
+            super(DATASTORE_METHODS[:delete])
+        end
+
+        # Replaces the template contents
+        #
+        # @param new_template [String] New template contents
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(new_template, append=false)
+            super(DATASTORE_METHODS[:update], new_template, append ? 1 : 0)
+        end
+
+        # Changes the owner/group
+        #
+        # @param uid [Integer] the new owner id. Set to -1 to leave the current one
+        # @param gid [Integer] the new group id. Set to -1 to leave the current one
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chown(uid, gid)
+            super(DATASTORE_METHODS[:chown], uid, gid)
+        end
+
+        # Changes the datastore permissions.
+        #
+        # @param octet [String] Permissions octed , e.g. 640
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod_octet(octet)
+            super(DATASTORE_METHODS[:chmod], octet)
+        end
+
+        # Changes the datastore permissions.
+        # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
+                other_m, other_a)
+            super(DATASTORE_METHODS[:chmod], owner_u, owner_m, owner_a, group_u,
+                group_m, group_a, other_u, other_m, other_a)
+        end
+
+        # Renames this datastore
+        #
+        # @param name [String] New name for the datastore
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def rename(name)
+            return call(DATASTORE_METHODS[:rename], @pe_id, name)
+        end
+
+        # ---------------------------------------------------------------------
+        # Helpers to get information
+        # ---------------------------------------------------------------------
+
+        # Returns whether or not the image with id 'id' is part of this datastore
+        def contains(id)
+            #This doesn't work in ruby 1.8.5
+            #return self["DATASTORE/ID[.=#{uid}]"] != nil
+
+            id_array = retrieve_elements('IMAGES/ID')
+            return id_array != nil && id_array.include?(uid.to_s)
+        end
+
+        # Returns an array with the numeric image ids
+        def img_ids
+            array = Array.new
+
+            self.each("IMAGES/ID") do |id|
+                array << id.text.to_i
+            end
+
+            return array
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/datastore_pool.rb b/ruby-opennebula-4.4/lib/opennebula/datastore_pool.rb
new file mode 100644 (file)
index 0000000..25bfef8
--- /dev/null
@@ -0,0 +1,55 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class DatastorePool < Pool
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+        DATASTORE_POOL_METHODS = {
+            :info => "datastorepool.info"
+        }
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+        # +client+ a Client object that represents a XML-RPC connection
+        def initialize(client)
+            super('DATASTORE_POOL','DATASTORE',client)
+        end
+
+        # Factory method to create User objects
+        def factory(element_xml)
+            OpenNebula::Group.new(element_xml,@client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the User Object
+        #######################################################################
+
+        # Retrieves all the Groups in the pool.
+        def info()
+            super(DATASTORE_POOL_METHODS[:info])
+        end
+
+        alias_method :info!, :info
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/document.rb b/ruby-opennebula-4.4/lib/opennebula/document.rb
new file mode 100644 (file)
index 0000000..2a519ef
--- /dev/null
@@ -0,0 +1,263 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+
+module OpenNebula
+
+    # All subclasses must define the DOCUMENT_TYPE constant.
+    #
+    # @example
+    #   require 'opennebula/document'
+    #
+    #   module OpenNebula
+    #       class CustomObject < Document
+    #
+    #           DOCUMENT_TYPE = 400
+    #
+    #       end
+    #   end
+    class Document < PoolElement
+
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+        DOCUMENT_METHODS = {
+            :allocate   => "document.allocate",
+            :delete     => "document.delete",
+            :info       => "document.info",
+            :update     => "document.update",
+            :chown      => "document.chown",
+            :chmod      => "document.chmod",
+            :clone      => "document.clone",
+            :rename     => "document.rename"
+        }
+
+        # Creates a Document Object description with just its identifier
+        # this method should be used to create plain Document objects.
+        # @param [Integer] pe_id the id of the object
+        #
+        # @return [Nokogiri::XML::Node, REXML::Element] the empty xml
+        def Document.build_xml(pe_id=nil)
+            if pe_id
+                obj_xml = "<DOCUMENT><ID>#{pe_id}</ID></DOCUMENT>"
+            else
+                obj_xml = "<DOCUMENT></DOCUMENT>"
+            end
+
+            XMLElement.build_xml(obj_xml,'DOCUMENT')
+        end
+
+        # Class constructor
+        #
+        # @param [Nokogiri::XML::Node, REXML::Element] xml string
+        #   created by the build_xml() method
+        # @param [OpenNebula::Client] client the xml-rpc client
+        #
+        # @return [Document] the new object
+        #
+        # @example
+        #   doc = Document.new(Document.build_xml(3),rpc_client)
+        def initialize(xml, client)
+            super(xml,client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Document Object
+        #######################################################################
+
+        # Retrieves the information of the given Document.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def info()
+            rc = super(DOCUMENT_METHODS[:info], 'DOCUMENT')
+
+            if !OpenNebula.is_error?(rc) && self['TYPE'].to_i != document_type
+                return OpenNebula::Error.new("[DocumentInfo] Error getting document [#{@pe_id}].")
+            end
+
+            return rc
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new Document in OpenNebula
+        #
+        # @param description [String] The contents of the Document.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def allocate(description)
+            super(DOCUMENT_METHODS[:allocate], description, document_type)
+        end
+
+        # Deletes the Document
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def delete()
+            rc = check_type()
+            return rc if OpenNebula.is_error?(rc)
+
+            return call(DOCUMENT_METHODS[:delete], @pe_id)
+        end
+
+        # Replaces the template contents
+        #
+        # @param [String] new_template new template contents
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(new_template, append=false)
+            rc = check_type()
+            return rc if OpenNebula.is_error?(rc)
+
+            super(DOCUMENT_METHODS[:update], new_template, append ? 1 : 0)
+        end
+
+        # Changes the owner/group
+        #
+        # @param [Integer] uid the new owner id. Set to -1 to leave the current one
+        # @param [Integer] gid the new group id. Set to -1 to leave the current one
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chown(uid, gid)
+            rc = check_type()
+            return rc if OpenNebula.is_error?(rc)
+
+            super(DOCUMENT_METHODS[:chown], uid, gid)
+        end
+
+        # Changes the Document permissions.
+        #
+        # @param octet [String] Permissions octed , e.g. 640
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod_octet(octet)
+            rc = check_type()
+            return rc if OpenNebula.is_error?(rc)
+
+            super(DOCUMENT_METHODS[:chmod], octet)
+        end
+
+        # Changes the Document permissions.
+        # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
+                other_m, other_a)
+            rc = check_type()
+            return rc if OpenNebula.is_error?(rc)
+
+            super(DOCUMENT_METHODS[:chmod], owner_u, owner_m, owner_a, group_u,
+                group_m, group_a, other_u, other_m, other_a)
+        end
+
+        # Clones this Document into a new one
+        #
+        # @param name [String] Name for the new Document.
+        #
+        # @return [Integer, OpenNebula::Error] The new Document ID in case
+        #   of success, Error otherwise
+        def clone(name)
+            rc = check_type()
+            return rc if OpenNebula.is_error?(rc)
+
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(DOCUMENT_METHODS[:clone], @pe_id, name)
+
+            return rc
+        end
+
+        # Renames this Document
+        #
+        # @param name [String] New name for the Document.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def rename(name)
+            return call(DOCUMENT_METHODS[:rename], @pe_id, name)
+        end
+
+        #######################################################################
+        # Helpers to get Document information
+        #######################################################################
+
+        # Returns the group identifier
+        # @return [Integer] the element's group ID
+        def gid
+            self['GID'].to_i
+        end
+
+        # Returns the owner user ID
+        # @return [Integer] the element's owner user ID
+        def owner_id
+            self['UID'].to_i
+        end
+
+        # Returns true if the GROUP_U permission bit is set
+        # @return [true, false] true if the GROUP_U permission bit is set
+        def public?
+            if self['PERMISSIONS/GROUP_U'] == "1" || self['PERMISSIONS/OTHER_U'] == "1"
+                true
+            else
+                false
+            end
+        end
+
+        def document_type
+            self.class::DOCUMENT_TYPE
+        end
+
+    private
+
+        def set_publish(published)
+            group_u = published ? 1 : 0
+
+            chmod(-1, -1, -1, group_u, -1, -1, -1, -1, -1)
+        end
+
+        def check_type()
+            type = self['TYPE']
+
+            if type.nil? && @pe_id
+                rc = @client.call(DOCUMENT_METHODS[:info], @pe_id)
+
+                return rc if OpenNebula.is_error?(rc)
+
+                xmldoc = XMLElement.new
+                xmldoc.initialize_xml(rc, 'DOCUMENT')
+
+                type = xmldoc['TYPE']
+            end
+
+            if !type.nil? && type.to_i != document_type
+                return OpenNebula::Error.new(
+                    "[DocumentInfo] Error getting document [#{@pe_id}].")
+            end
+
+            return nil
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/document_json.rb b/ruby-opennebula-4.4/lib/opennebula/document_json.rb
new file mode 100644 (file)
index 0000000..fdbb680
--- /dev/null
@@ -0,0 +1,134 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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'
+
+module OpenNebula
+    class DocumentJSON < Document
+
+        TEMPLATE_TAG = "BODY"
+
+        # Allocate a new Document containing the json inside the TEMPLATE
+        #
+        # @param [String] template_json json to be inserted in the TEMPLATE
+        #   of the new resource
+        # @param [String, nil] name name of the object, this value will be
+        #   processed by the OpenNebula core
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        #
+        def allocate(template_json, name=nil)
+            text = build_template_xml(template_json, name)
+
+            super(text)
+        end
+
+        # Retrieves the information of the Service and all its Nodes.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        #
+        def info
+            rc = super
+            if OpenNebula.is_error?(rc)
+                return rc
+            end
+
+            load_body
+        end
+
+        alias_method :info!, :info
+
+        # Updates the current state of this Service in the OpenNebula DB
+        #
+        # @params [String, nil] template_json string to be inserted in the
+        #   template. If nil @body will be used instead
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        #
+        def update(template_json=nil, append=false)
+            template_json ||= @body.to_json
+
+            text = build_template_xml(template_json)
+
+            super(text, append)
+        end
+
+        # Generates a json representing the object
+        #
+        # @param [true, false] pretty_generate
+        # @return [String] json representing the object
+        #
+        def to_json(pretty_generate=true)
+            hash = self.to_hash
+
+            body = hash['DOCUMENT']['TEMPLATE']["#{TEMPLATE_TAG}"]
+            if body
+                body_hash = JSON.parse(body)
+                hash['DOCUMENT']['TEMPLATE']["#{TEMPLATE_TAG}"] = body_hash
+            end
+
+            if pretty_generate
+                JSON.pretty_generate hash
+            else
+                hash.to_json
+            end
+        end
+
+
+        # Fill the @body hash with the values of the template
+        def load_body
+            body_str = self["TEMPLATE/#{TEMPLATE_TAG}"]
+
+            if body_str
+                begin
+                    @body = JSON.parse(body_str)
+                rescue JSON::JSONError
+                    return OpenNebula::Error.new($!)
+                end
+            end
+
+            return nil
+        end
+
+        private
+
+        # Build an xml string incluiding the provided json
+        #
+        # @param [String] template_json The template to be inserted
+        # @param [String, nil] name The string to be inserted as name
+        # @return [String] The xml containing the json
+        #
+        def build_template_xml(template_json, name=nil)
+            template_json ||= ""
+
+            text = "<TEMPLATE>"
+
+            text << "<NAME>#{name}</NAME>" if name
+
+            text << "<#{TEMPLATE_TAG}>"
+            text << "<![CDATA[#{template_json}]]>"
+            text << "</#{TEMPLATE_TAG}>"
+
+            text << "</TEMPLATE>"
+
+            text
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/document_pool.rb b/ruby-opennebula-4.4/lib/opennebula/document_pool.rb
new file mode 100644 (file)
index 0000000..dfd1c96
--- /dev/null
@@ -0,0 +1,102 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+
+    # All subclasses must define the DOCUMENT_TYPE constant
+    # and the factory method.
+    #
+    # @example
+    #   require 'opennebuña/document_pool'
+    #
+    #   module OpenNebula
+    #       class CustomObjectPool < DocumentPool
+    #
+    #           DOCUMENT_TYPE = 400
+    #
+    #           def factory(element_xml)
+    #               OpenNebula::CustomObject.new(element_xml, @client)
+    #           end
+    #       end
+    #   end
+    class DocumentPool < Pool
+
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+        DOCUMENT_POOL_METHODS = {
+            :info => "documentpool.info"
+        }
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+        # Class constructor
+        #
+        # @param [OpenNebula::Client] client the xml-rpc client
+        # @param [Integer] user_id the filter flag, see
+        #   http://opennebula.org/documentation:rel3.6:api
+        #
+        # @return [DocumentPool] the new object
+        def initialize(client, user_id=-1)
+            super('DOCUMENT_POOL','DOCUMENT',client)
+
+            @user_id  = user_id
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Document Object
+        #######################################################################
+
+        # Retrieves all or part of the Documents in the pool.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def info(*args)
+            case args.size
+                when 0
+                    info_filter(DOCUMENT_POOL_METHODS[:info],@user_id,-1,-1, document_type)
+                when 3
+                    info_filter(DOCUMENT_POOL_METHODS[:info],args[0],args[1],args[2], document_type)
+            end
+        end
+
+        def info_all()
+            return super(DOCUMENT_POOL_METHODS[:info], document_type)
+        end
+
+        def info_mine()
+            return super(DOCUMENT_POOL_METHODS[:info], document_type)
+        end
+
+        def info_group()
+            return super(DOCUMENT_POOL_METHODS[:info], document_type)
+        end
+
+        alias_method :info!, :info
+        alias_method :info_all!, :info_all
+        alias_method :info_mine!, :info_mine
+        alias_method :info_group!, :info_group
+
+        def document_type
+            self.class::DOCUMENT_TYPE
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/document_pool_json.rb b/ruby-opennebula-4.4/lib/opennebula/document_pool_json.rb
new file mode 100644 (file)
index 0000000..8097dca
--- /dev/null
@@ -0,0 +1,58 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 OpenNebula
+    class DocumentPoolJSON < DocumentPool
+
+        TEMPLATE_TAG = "BODY"
+
+        def factory(element_xml)
+            doc = OpenNebula::DocumentJSON.new(element_xml, @client)
+            doc.load_body
+            doc
+        end
+
+        # Generates a json representing the object
+        #
+        # @param [true, false] pretty_generate
+        # @return [String] json representing the object
+        #
+        def to_json(pretty_generate=true)
+            hash = self.to_hash
+
+            if hash['DOCUMENT_POOL'] && hash['DOCUMENT_POOL']['DOCUMENT']
+                if !hash['DOCUMENT_POOL']['DOCUMENT'].instance_of?(Array)
+                    array = [hash['DOCUMENT_POOL']['DOCUMENT']]
+                    hash['DOCUMENT_POOL']['DOCUMENT'] = array.compact
+                end
+
+                hash['DOCUMENT_POOL']['DOCUMENT'].each { |doc|
+                    body = doc['TEMPLATE']["#{TEMPLATE_TAG}"]
+                    if body
+                        b_hash = JSON.parse(body)
+                        doc['TEMPLATE']["#{TEMPLATE_TAG}"] = b_hash
+                    end
+                }
+            end
+
+            if pretty_generate
+                JSON.pretty_generate hash
+            else
+                hash.to_json
+            end
+        end
+    end
+end
\ No newline at end of file
diff --git a/ruby-opennebula-4.4/lib/opennebula/error.rb b/ruby-opennebula-4.4/lib/opennebula/error.rb
new file mode 100644 (file)
index 0000000..e3081b0
--- /dev/null
@@ -0,0 +1,52 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 OpenNebula
+    # The Error Class represents a generic error in the OpenNebula
+    # library. It contains a readable representation of the error.
+    # Any function in the OpenNebula module will return an Error
+    # object in case of error.
+    class Error
+        ESUCCESS        = 0x0000
+        EAUTHENTICATION = 0x0100
+        EAUTHORIZATION  = 0x0200
+        ENO_EXISTS      = 0x0400
+        EACTION         = 0x0800
+        EXML_RPC_API    = 0x1000
+        EINTERNAL       = 0x2000
+        ENOTDEFINED     = 0x1111
+
+        attr_reader :message, :errno
+
+        # +message+ Description of the error
+        # +errno+   OpenNebula code error
+        def initialize(message=nil, errno=0x1111)
+            @message = message
+            @errno   = errno
+        end
+
+        def to_str()
+            @message
+        end
+    end
+
+    # Returns true if the object returned by a method of the OpenNebula
+    # library is an Error
+    def self.is_error?(value)
+        value.class==OpenNebula::Error
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/group.rb b/ruby-opennebula-4.4/lib/opennebula/group.rb
new file mode 100644 (file)
index 0000000..6a8fc15
--- /dev/null
@@ -0,0 +1,163 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+
+module OpenNebula
+    class Group < PoolElement
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+        GROUP_METHODS = {
+            :info     => "group.info",
+            :allocate => "group.allocate",
+            :delete   => "group.delete",
+            :quota    => "group.quota"
+        }
+
+        # Flag for requesting connected user's group info
+        SELF = -1
+
+        #Default location for group ACL's
+        if ENV['ONE_LOCATION']
+            GROUP_DEFAULT = ENV['ONE_LOCATION'] + "/etc/group.default"
+        else
+            GROUP_DEFAULT = "/etc/one/group.default"
+        end
+
+        # Creates a Group description with just its identifier
+        # this method should be used to create plain Group objects.
+        # +id+ the id of the user
+        #
+        # Example:
+        #   group = Group.new(Group.build_xml(3),rpc_client)
+        #
+        def Group.build_xml(pe_id=nil)
+            if pe_id
+                group_xml = "<GROUP><ID>#{pe_id}</ID></GROUP>"
+            else
+                group_xml = "<GROUP></GROUP>"
+            end
+
+            XMLElement.build_xml(group_xml,'GROUP')
+        end
+
+        # Class constructor
+        def initialize(xml, client)
+            super(xml,client)
+        end
+
+        #######################################################################
+        # Group utils
+        #######################################################################
+
+        # Creates ACLs for the group. The ACL rules are described in a file
+        def create_acls(filename = GROUP_DEFAULT)
+            if !File.readable?(filename)
+                return -1, "Cannot read deafult ACL file for group"
+            end
+
+            msg = String.new
+
+            File.open(filename).each_line{ |l|
+                next if l.match(/^#/)
+
+                rule  = "@#{@pe_id} #{l}"
+                parse = OpenNebula::Acl.parse_rule(rule)
+
+                if OpenNebula.is_error?(parse)
+                    return -1, "Error parsing rule #{rule}: #{parse.message}"
+                end
+
+                xml = OpenNebula::Acl.build_xml
+                acl = OpenNebula::Acl.new(xml, @client)
+
+                rc = acl.allocate(*parse)
+
+                if OpenNebula.is_error?(rc)
+                    return -1, "Error creating rule #{rule}: #{rc.message}"
+                else
+                    msg << "ACL_ID: #{acl.id}\n"
+                end
+            }
+
+            return 0, msg
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Group Object
+        #######################################################################
+
+        # Retrieves the information of the given Group.
+        def info()
+            super(GROUP_METHODS[:info], 'GROUP')
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new Group in OpenNebula
+        #
+        # +groupname+ A string containing the name of the Group.
+        def allocate(groupname)
+            super(GROUP_METHODS[:allocate], groupname)
+        end
+
+        # Deletes the Group
+        def delete()
+            super(GROUP_METHODS[:delete])
+        end
+
+        # Sets the group quota limits
+        # @param quota [String] a template (XML or txt) with the new quota limits 
+        # 
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def set_quota(quota)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(GROUP_METHODS[:quota],@pe_id, quota)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # ---------------------------------------------------------------------
+        # Helpers to get information
+        # ---------------------------------------------------------------------
+
+        # Returns whether or not the user with id 'uid' is part of this group
+        def contains(uid)
+            #This doesn't work in ruby 1.8.5
+            #return self["USERS/ID[.=#{uid}]"] != nil
+
+            id_array = retrieve_elements('USERS/ID')
+            return id_array != nil && id_array.include?(uid.to_s)
+        end
+
+        # Returns an array with the numeric user ids
+        def user_ids
+            array = Array.new
+
+            self.each("USERS/ID") do |id|
+                array << id.text.to_i
+            end
+
+            return array
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/group_pool.rb b/ruby-opennebula-4.4/lib/opennebula/group_pool.rb
new file mode 100644 (file)
index 0000000..bd5deee
--- /dev/null
@@ -0,0 +1,56 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class GroupPool < Pool
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+
+        GROUP_POOL_METHODS = {
+            :info => "grouppool.info"
+        }
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+        # +client+ a Client object that represents a XML-RPC connection
+        def initialize(client)
+            super('GROUP_POOL','GROUP',client)
+        end
+
+        # Factory method to create User objects
+        def factory(element_xml)
+            OpenNebula::Group.new(element_xml,@client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the User Object
+        #######################################################################
+
+        # Retrieves all the Groups in the pool.
+        def info()
+            super(GROUP_POOL_METHODS[:info])
+        end
+
+        alias_method :info!, :info
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/host.rb b/ruby-opennebula-4.4/lib/opennebula/host.rb
new file mode 100644 (file)
index 0000000..7476e01
--- /dev/null
@@ -0,0 +1,219 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+
+module OpenNebula
+    class Host < PoolElement
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+
+        HOST_METHODS = {
+            :info       => "host.info",
+            :allocate   => "host.allocate",
+            :delete     => "host.delete",
+            :enable     => "host.enable",
+            :update     => "host.update",
+            :monitoring => "host.monitoring",
+            :rename     => "host.rename"
+        }
+
+        HOST_STATES=%w{INIT MONITORING_MONITORED MONITORED ERROR DISABLED MONITORING_ERROR MONITORING_INIT MONITORING_DISABLED}
+
+        SHORT_HOST_STATES={
+            "INIT"                 => "init",
+            "MONITORING_MONITORED" => "update",
+            "MONITORED"            => "on",
+            "ERROR"                => "err",
+            "DISABLED"             => "off",
+            "MONITORING_ERROR"     => "retry",
+            "MONITORING_INIT"      => "init",
+            "MONITORING_DISABLED"  => "off"
+        }
+
+        # Creates a Host description with just its identifier
+        # this method should be used to create plain Host objects.
+        # +id+ the id of the host
+        #
+        # Example:
+        #   host = Host.new(Host.build_xml(3),rpc_client)
+        #
+        def Host.build_xml(pe_id=nil)
+            if pe_id
+                host_xml = "<HOST><ID>#{pe_id}</ID></HOST>"
+            else
+                host_xml = "<HOST></HOST>"
+            end
+
+            XMLElement.build_xml(host_xml, 'HOST')
+        end
+
+        # Class constructor
+        def initialize(xml, client)
+            super(xml,client)
+
+            @client = client
+            @pe_id  = self['ID'].to_i if self['ID']
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Host
+        #######################################################################
+
+        # Retrieves the information of the given Host.
+        def info()
+            super(HOST_METHODS[:info], 'HOST')
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new Host in OpenNebula
+        #
+        # @param hostname [String] Name of the new Host.
+        # @param im [String] Name of the im_driver (information/monitoring)
+        # @param vmm [String] Name of the vmm_driver (hypervisor)
+        # @param vnm [String] Name of the vnm_driver (networking)
+        # @param cluster_id [String] Id of the cluster
+        #
+        # @return [Integer, OpenNebula::Error] the new ID in case of
+        #   success, error otherwise
+        def allocate(hostname,im,vmm,vnm,cluster_id=ClusterPool::NONE_CLUSTER_ID)
+            super(HOST_METHODS[:allocate],hostname,im,vmm,vnm,cluster_id)
+        end
+
+        # Deletes the Host
+        def delete()
+            super(HOST_METHODS[:delete])
+        end
+
+        # Enables the Host
+        def enable()
+            set_enabled(true)
+        end
+
+        # Disables the Host
+        def disable()
+            set_enabled(false)
+        end
+
+        def flush()
+            self.disable
+
+            vm_pool = OpenNebula::VirtualMachinePool.new(@client,
+                                                VirtualMachinePool::INFO_ALL_VM)
+
+            rc = vm_pool.info
+            if OpenNebula.is_error?(rc)
+                 puts rc.message
+                 exit -1
+            end
+
+            vm_pool.each do |vm|
+                hid = vm['HISTORY_RECORDS/HISTORY[last()]/HID']
+                if hid == self['ID']
+                    vm.resched
+                end
+            end
+        end
+
+        # Replaces the template contents
+        #
+        # @param new_template [String] New template contents
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(new_template, append=false)
+            super(HOST_METHODS[:update], new_template, append ? 1 : 0)
+        end
+
+        # Retrieves this Host's monitoring data from OpenNebula
+        #
+        # @param [Array<String>] xpath_expressions Elements to retrieve.
+        #
+        # @return [Hash<String, Array<Array<int>>>, OpenNebula::Error] Hash with
+        #   the requested xpath expressions, and an Array of 'timestamp, value'.
+        #
+        # @example
+        #   host.monitoring( ['HOST_SHARE/FREE_CPU', 'HOST_SHARE/RUNNING_VMS'] )
+        #
+        #   { "HOST_SHARE/RUNNING_VMS" =>
+        #       [["1337266000", "1"],
+        #        ["1337266044", "1"],
+        #        ["1337266088", "3"]],
+        #     "HOST_SHARE/FREE_CPU" =>
+        #       [["1337266000", "800"],
+        #        ["1337266044", "800"],
+        #        ["1337266088", "800"]]
+        #   }
+        def monitoring(xpath_expressions)
+            return super(HOST_METHODS[:monitoring], 'HOST',
+                'LAST_MON_TIME', xpath_expressions)
+        end
+
+        # Retrieves this Host's monitoring data from OpenNebula, in XML
+        #
+        # @return [String] Monitoring data, in XML
+        def monitoring_xml()
+            return Error.new('ID not defined') if !@pe_id
+
+            return @client.call(HOST_METHODS[:monitoring], @pe_id)
+        end
+
+        # Renames this Host
+        #
+        # @param name [String] New name for the Host.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def rename(name)
+            return call(HOST_METHODS[:rename], @pe_id, name)
+        end
+
+        #######################################################################
+        # Helpers to get Host information
+        #######################################################################
+
+        # Returns the state of the Host (numeric value)
+        def state
+            self['STATE'].to_i
+        end
+
+        # Returns the state of the Host (string value)
+        def state_str
+            HOST_STATES[state]
+        end
+
+        # Returns the state of the Host (string value)
+        def short_state_str
+            SHORT_HOST_STATES[state_str]
+        end
+
+    private
+        def set_enabled(enabled)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(HOST_METHODS[:enable], @pe_id, enabled)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/host_pool.rb b/ruby-opennebula-4.4/lib/opennebula/host_pool.rb
new file mode 100644 (file)
index 0000000..c36ff0b
--- /dev/null
@@ -0,0 +1,93 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class HostPool < Pool
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+
+        HOST_POOL_METHODS = {
+            :info       => "hostpool.info",
+            :monitoring => "hostpool.monitoring"
+        }
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+
+        # +client+ a Client object that represents a XML-RPC connection
+        def initialize(client)
+            super('HOST_POOL','HOST',client)
+        end
+
+        # Factory Method for the Host Pool
+        def factory(element_xml)
+            OpenNebula::Host.new(element_xml,@client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Host Pool 
+        #######################################################################
+
+        # Retrieves all the Hosts in the pool.
+        def info()
+            super(HOST_POOL_METHODS[:info])
+        end
+
+        alias_method :info!, :info
+
+        # Retrieves the monitoring data for all the Hosts in the pool
+        #
+        # @param [Array<String>] xpath_expressions Elements to retrieve.
+        #
+        # @return [Hash<String, <Hash<String, Array<Array<int>>>>>,
+        #   OpenNebula::Error] The first level hash uses the Host ID as keys,
+        #   and as value a Hash with the requested xpath expressions,
+        #   and an Array of 'timestamp, value'.
+        #
+        # @example
+        #   host_pool.monitoring(
+        #     ['HOST_SHARE/FREE_CPU',
+        #     'HOST_SHARE/RUNNING_VMS',
+        #     'TEMPLATE/CUSTOM_PROBE'] )
+        #
+        #   {"1"=>
+        #     {"TEMPLATE/CUSTOM_PROBE"=>[],
+        #      "HOST_SHARE/FREE_CPU"=>[["1337609673", "800"]],
+        #      "HOST_SHARE/RUNNING_VMS"=>[["1337609673", "3"]]},
+        #    "0"=>
+        #     {"TEMPLATE/CUSTOM_PROBE"=>[],
+        #      "HOST_SHARE/FREE_CPU"=>[["1337609673", "800"]],
+        #      "HOST_SHARE/RUNNING_VMS"=>[["1337609673", "3"]]}}
+        def monitoring(xpath_expressions)
+            return super(HOST_POOL_METHODS[:monitoring],
+                'HOST', 'LAST_MON_TIME', xpath_expressions)
+        end
+
+        # Retrieves the monitoring data for all the Hosts in the pool, in XML
+        #
+        # @return [String] VM monitoring data, in XML
+        def monitoring_xml()
+            return @client.call(HOST_POOL_METHODS[:monitoring])
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/image.rb b/ruby-opennebula-4.4/lib/opennebula/image.rb
new file mode 100644 (file)
index 0000000..05330ed
--- /dev/null
@@ -0,0 +1,301 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+require 'fileutils'
+
+module OpenNebula
+    class Image < PoolElement
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+
+        IMAGE_METHODS = {
+            :info        => "image.info",
+            :allocate    => "image.allocate",
+            :update      => "image.update",
+            :enable      => "image.enable",
+            :persistent  => "image.persistent",
+            :delete      => "image.delete",
+            :chown       => "image.chown",
+            :chmod       => "image.chmod",
+            :chtype      => "image.chtype",
+            :clone       => "image.clone",
+            :rename      => "image.rename"
+        }
+
+        IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR CLONE DELETE USED_PERS}
+
+        SHORT_IMAGE_STATES={
+            "INIT"      => "init",
+            "READY"     => "rdy",
+            "USED"      => "used",
+            "DISABLED"  => "disa",
+            "LOCKED"    => "lock",
+            "ERROR"     => "err",
+            "CLONE"     => "clon",
+            "DELETE"    => "dele",
+            "USED_PERS" => "used"
+        }
+
+        IMAGE_TYPES=%w{OS CDROM DATABLOCK KERNEL RAMDISK CONTEXT}
+
+        SHORT_IMAGE_TYPES={
+            "OS"        => "OS",
+            "CDROM"     => "CD",
+            "DATABLOCK" => "DB",
+            "KERNEL"    => "KL",
+            "RAMDISK"   => "RD",
+            "CONTEXT"   => "CX"
+        }
+
+        DISK_TYPES=%w{FILE CD_ROM BLOCK RBD}
+
+        # Creates an Image description with just its identifier
+        # this method should be used to create plain Image objects.
+        # +id+ the id of the image
+        #
+        # Example:
+        #   image = Image.new(Image.build_xml(3),rpc_client)
+        #
+        def Image.build_xml(pe_id=nil)
+            if pe_id
+                image_xml = "<IMAGE><ID>#{pe_id}</ID></IMAGE>"
+            else
+                image_xml = "<IMAGE></IMAGE>"
+            end
+
+            XMLElement.build_xml(image_xml,'IMAGE')
+        end
+
+        # Class constructor
+        def initialize(xml, client)
+            super(xml,client)
+
+            @client = client
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Image Object
+        #######################################################################
+
+        # Retrieves the information of the given Image.
+        def info()
+            super(IMAGE_METHODS[:info], 'IMAGE')
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new Image in OpenNebula
+        #
+        # @param description [String] A string containing the template of the Image.
+        # @param ds_id [Integer] the target datastore ID
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def allocate(description, ds_id)
+            super(IMAGE_METHODS[:allocate],description, ds_id)
+        end
+
+        # Replaces the template contents
+        #
+        # @param new_template [String] New template contents
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(new_template=nil, append=false)
+            super(IMAGE_METHODS[:update], new_template, append ? 1 : 0)
+        end
+
+        # Enables an Image
+        def enable
+            set_enabled(true)
+        end
+
+        # Disables an Image
+        def disable
+            set_enabled(false)
+        end
+
+        # Publishes the Image, to be used by other users
+        def publish
+            set_publish(true)
+        end
+
+        # Unplubishes the Image
+        def unpublish
+            set_publish(false)
+        end
+
+        # Makes the Image persistent
+        def persistent
+            set_persistent(true)
+        end
+
+        # Makes the Image non persistent
+        def nonpersistent
+            set_persistent(false)
+        end
+
+        # Deletes the Image
+        def delete()
+            super(IMAGE_METHODS[:delete])
+        end
+
+        # Changes the owner/group
+        # uid:: _Integer_ the new owner id. Set to -1 to leave the current one
+        # gid:: _Integer_ the new group id. Set to -1 to leave the current one
+        # [return] nil in case of success or an Error object
+        def chown(uid, gid)
+            super(IMAGE_METHODS[:chown], uid, gid)
+        end
+
+        # Changes the Image permissions.
+        #
+        # @param octet [String] Permissions octed , e.g. 640
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod_octet(octet)
+            super(IMAGE_METHODS[:chmod], octet)
+        end
+
+        # Changes the Image permissions.
+        # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
+                other_m, other_a)
+            super(IMAGE_METHODS[:chmod], owner_u, owner_m, owner_a, group_u,
+                group_m, group_a, other_u, other_m, other_a)
+        end
+
+        # Changes the Image type
+        # @param type [String] new Image type
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chtype(type)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(IMAGE_METHODS[:chtype], @pe_id, type)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Clones this Image into a new one
+        #
+        # @param [String] name for the new Image.
+        #
+        # @return [Integer, OpenNebula::Error] The new Image ID in case
+        #   of success, Error otherwise
+        def clone(name)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(IMAGE_METHODS[:clone], @pe_id, name)
+
+            return rc
+        end
+
+        # Renames this Image
+        #
+        # @param name [String] New name for the Image.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def rename(name)
+            return call(IMAGE_METHODS[:rename], @pe_id, name)
+        end
+
+        #######################################################################
+        # Helpers to get Image information
+        #######################################################################
+
+        # Returns the state of the Image (numeric value)
+        def state
+            self['STATE'].to_i
+        end
+
+        # Returns the state of the Image (string value)
+        def state_str
+            IMAGE_STATES[state]
+        end
+
+        # Returns the state of the Image (string value)
+        def short_state_str
+            SHORT_IMAGE_STATES[state_str]
+        end
+
+        # Returns the type of the Image (numeric value)
+        def type
+            self['TYPE'].to_i
+        end
+
+        # Returns the type of the Image (string value)
+        def type_str
+            IMAGE_TYPES[type]
+        end
+
+        # Returns the state of the Image (string value)
+        def short_type_str
+            SHORT_IMAGE_TYPES[type_str]
+        end
+
+        # Returns the group identifier
+        # [return] _Integer_ the element's group ID
+        def gid
+            self['GID'].to_i
+        end
+
+        def public?
+            if self['PERMISSIONS/GROUP_U'] == "1" || self['PERMISSIONS/OTHER_U'] == "1"
+                true
+            else
+                false
+            end
+        end
+
+    private
+
+        def set_enabled(enabled)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(IMAGE_METHODS[:enable], @pe_id, enabled)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        def set_publish(published)
+            group_u = published ? 1 : 0
+
+            chmod(-1, -1, -1, group_u, -1, -1, -1, -1, -1)
+        end
+
+        def set_persistent(persistence)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(IMAGE_METHODS[:persistent], @pe_id, persistence)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/image_pool.rb b/ruby-opennebula-4.4/lib/opennebula/image_pool.rb
new file mode 100644 (file)
index 0000000..545742d
--- /dev/null
@@ -0,0 +1,79 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class ImagePool < Pool
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+
+        IMAGE_POOL_METHODS = {
+            :info => "imagepool.info"
+        }
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+        # +client+ a Client object that represents a XML-RPC connection
+        # +user_id+ is to refer to a Pool with Images from that user
+        def initialize(client, user_id=-1)
+            super('IMAGE_POOL','IMAGE',client)
+
+            @user_id  = user_id
+        end
+
+        # Default Factory Method for the Pools
+        def factory(element_xml)
+            OpenNebula::Image.new(element_xml,@client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Image Object
+        #######################################################################
+
+        # Retrieves all or part of the VirtualMachines in the pool.
+        def info(*args)
+            case args.size
+                when 0
+                    info_filter(IMAGE_POOL_METHODS[:info],@user_id,-1,-1)
+                when 3
+                    info_filter(IMAGE_POOL_METHODS[:info],args[0],args[1],args[2])
+            end
+        end
+
+        def info_all()
+            return super(IMAGE_POOL_METHODS[:info])
+        end
+
+        def info_mine()
+            return super(IMAGE_POOL_METHODS[:info])
+        end
+
+        def info_group()
+            return super(IMAGE_POOL_METHODS[:info])
+        end
+
+        alias_method :info!, :info
+        alias_method :info_all!, :info_all
+        alias_method :info_mine!, :info_mine
+        alias_method :info_group!, :info_group
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/ldap_auth.rb b/ruby-opennebula-4.4/lib/opennebula/ldap_auth.rb
new file mode 100644 (file)
index 0000000..b6d965f
--- /dev/null
@@ -0,0 +1,103 @@
+# ---------------------------------------------------------------------------- #
+# Copyright 2010-2013, C12G Labs S.L                                           #
+#                                                                              #
+# Licensed under the Apache License, Version 2.0 (the "License"); you may      #
+# not use this file except in compliance with the License. You may obtain      #
+# a copy of the License at                                                     #
+#                                                                              #
+# http://www.apache.org/licenses/LICENSE-2.0                                   #
+#                                                                              #
+# Unless required by applicable law or agreed to in writing, software          #
+# distributed under the License is distributed on an "AS IS" BASIS,            #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.     #
+# See the License for the specific language governing permissions and          #
+# limitations under the License.                                               #
+# ---------------------------------------------------------------------------- #
+
+require 'rubygems'
+require 'net/ldap'
+
+module OpenNebula; end
+
+class OpenNebula::LdapAuth
+    def initialize(options)
+        @options={
+            :host => 'localhost',
+            :port => 389,
+            :user => nil,
+            :password => nil,
+            :base => nil,
+            :auth_method => :simple,
+            :user_field => 'cn',
+            :user_group_field => 'dn',
+            :group_field => 'member'
+        }.merge(options)
+
+        ops={}
+
+        if @options[:user]
+            ops[:auth] = {
+                :method => @options[:auth_method],
+                :username => @options[:user],
+                :password => @options[:password]
+            }
+        end
+
+        ops[:host]=@options[:host] if @options[:host]
+        ops[:port]=@options[:port].to_i if @options[:port]
+        ops[:encryption]=@options[:encryption] if @options[:encryption]
+
+        @ldap=Net::LDAP.new(ops)
+    end
+
+    def find_user(name)
+        begin
+            result=@ldap.search(
+                :base => @options[:base],
+                :filter => "#{@options[:user_field]}=#{name}")
+
+            if result && result.first
+                [result.first.dn, result.first[@options[:user_group_field]]]
+            else
+                result=@ldap.search(:base => name)
+
+                if result && result.first
+                    [name, result.first[@options[:user_group_field]]]
+                else
+                    [nil, nil]
+                end
+            end
+        rescue
+            [nil, nil]
+        end
+    end
+
+    def is_in_group?(user, group)
+        result=@ldap.search(
+                    :base   => group,
+                    :filter => "(#{@options[:group_field]}=#{user.first})")
+
+        if result && result.first
+            true
+        else
+            false
+        end
+    end
+
+    def authenticate(user, password)
+        ldap=@ldap.clone
+
+        auth={
+            :method => @options[:auth_method],
+            :username => user,
+            :password => password
+        }
+
+        if ldap.bind(auth)
+            true
+        else
+            false
+        end
+    end
+end
+
diff --git a/ruby-opennebula-4.4/lib/opennebula/ldap_auth_spec.rb b/ruby-opennebula-4.4/lib/opennebula/ldap_auth_spec.rb
new file mode 100644 (file)
index 0000000..5fb8b5c
--- /dev/null
@@ -0,0 +1,74 @@
+# ---------------------------------------------------------------------------- #
+# Copyright 2010-2013, C12G Labs S.L                                           #
+#                                                                              #
+# 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 'ldap_auth'
+
+options={
+    :host => 'ubuntu-test',
+    :base => 'dc=localdomain'
+}
+
+describe LdapAuth do
+    before(:all) do
+        @ldap=LdapAuth.new(options)
+    end
+
+    it 'should find user dn' do
+        name,group_name=@ldap.find_user('user01')
+        name.should=='cn=user01,dc=localdomain'
+        group_name.should=='cn=user01,dc=localdomain'
+
+        name,group_name=@ldap.find_user('user02')
+        name.should=='cn=user02,dc=localdomain'
+        group_name.should=='cn=user02,dc=localdomain'
+
+        name,group_name=@ldap.find_user('user03')
+        name.should==nil
+        group_name.should==nil
+
+        name=@ldap.find_user('cn=user01,dc=localdomain')
+        name.should=='cn=user01,dc=localdomain'
+        group_name.should=='cn=user01,dc=localdomain'
+    end
+
+    it 'should tell if a user is in a group' do
+        group='cn=cloud,ou=groups,dc=localdomain'
+
+        result=@ldap.is_in_group?('cn=user01,dc=localdomain', group)
+        result.should==true
+
+        result=@ldap.is_in_group?('cn=user02,dc=localdomain', group)
+        result.should==false
+    end
+
+    it 'should authenticate user' do
+        result=@ldap.authenticate('cn=user01,dc=localdomain', 'password01')
+        result.should==true
+
+        result=@ldap.authenticate('cn=user02,dc=localdomain', 'password02')
+        result.should==true
+
+        result=@ldap.authenticate('cn=user01,dc=localdomain', 'password02')
+        result.should==false
+
+        result=@ldap.authenticate('user01,dc=localdomain', 'password01')
+        result.should==false
+    end
+
+end
+
diff --git a/ruby-opennebula-4.4/lib/opennebula/oneflow_client.rb b/ruby-opennebula-4.4/lib/opennebula/oneflow_client.rb
new file mode 100644 (file)
index 0000000..d0a8d7f
--- /dev/null
@@ -0,0 +1,387 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2010-2013, C12G Labs S.L.                                        #
+#                                                                            #
+# 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 'uri'
+require 'cloud/CloudClient'
+
+include CloudCLI
+
+module Role
+    # Actions that can be performed on the VMs of a given Role
+    SCHEDULE_ACTIONS = [
+        'shutdown',
+        'shutdown-hard',
+        'undeploy',
+        'undeploy-hard',
+        'hold',
+        'release',
+        'stop',
+        'suspend',
+        'resume',
+        'boot',
+        'delete',
+        'delete-recreate',
+        'reboot',
+        'reboot-hard',
+        'poweroff',
+        'poweroff-hard',
+        'snapshot-create'
+    ]
+
+    STATE = {
+        'PENDING'            => 0,
+        'DEPLOYING'          => 1,
+        'RUNNING'            => 2,
+        'UNDEPLOYING'        => 3,
+        'WARNING'            => 4,
+        'DONE'               => 5,
+        'FAILED_UNDEPLOYING' => 6,
+        'FAILED_DEPLOYING'   => 7,
+        'SCALING'            => 8,
+        'FAILED_SCALING'     => 9,
+        'COOLDOWN'           => 10
+    }
+
+    STATE_STR = [
+        'PENDING',
+        'DEPLOYING',
+        'RUNNING',
+        'UNDEPLOYING',
+        'WARNING',
+        'DONE',
+        'FAILED_UNDEPLOYING',
+        'FAILED_DEPLOYING',
+        'SCALING',
+        'FAILED_SCALING',
+        'COOLDOWN'
+    ]
+
+    # Returns the string representation of the role state
+    # @param [String] state String number representing the state
+    # @return the state string
+    def self.state_str(state_number)
+        return STATE_STR[state_number.to_i]
+    end
+end
+
+module Service
+
+    STATE = {
+        'PENDING'            => 0,
+        'DEPLOYING'          => 1,
+        'RUNNING'            => 2,
+        'UNDEPLOYING'        => 3,
+        'WARNING'            => 4,
+        'DONE'               => 5,
+        'FAILED_UNDEPLOYING' => 6,
+        'FAILED_DEPLOYING'   => 7,
+        'SCALING'            => 8,
+        'FAILED_SCALING'     => 9,
+        'COOLDOWN'           => 10
+    }
+
+    STATE_STR = [
+        'PENDING',
+        'DEPLOYING',
+        'RUNNING',
+        'UNDEPLOYING',
+        'WARNING',
+        'DONE',
+        'FAILED_UNDEPLOYING',
+        'FAILED_DEPLOYING',
+        'SCALING',
+        'FAILED_SCALING',
+        'COOLDOWN'
+    ]
+
+    # Returns the string representation of the service state
+    # @param [String] state String number representing the state
+    # @return the state string
+    def self.state_str(state_number)
+        return STATE_STR[state_number.to_i]
+    end
+
+    # Build a json specifying an action
+    # @param [String] perform action to be performed (i.e: shutdowm)
+    # @param [Hash, nil] params contains the params for the action
+    # @return [String] json representing the action
+    def self.build_json_action(perform, params=nil)
+        body = Hash.new
+        body['perform'] = perform
+        body['params']  = params if params
+
+        action = Hash.new
+        action['action'] = body
+
+        JSON.pretty_generate action
+    end
+
+    # CLI options
+
+    DEFAULT_OPTIONS = [
+        ENDPOINT = {
+            :name => "server",
+            :short => "-s url",
+            :large => "--server url",
+            :format => String,
+            :description => "Service endpoint"
+        },
+        USERNAME={
+            :name => "username",
+            :short => "-u name",
+            :large => "--username name",
+            :format => String,
+            :description => "User name"
+        },
+        PASSWORD={
+            :name => "password",
+            :short => "-p pass",
+            :large => "--password pass",
+            :format => String,
+            :description => "User password"
+        }
+    ]
+
+    JSON_FORMAT = {
+        :name => "json",
+        :short => "-j",
+        :large => "--json",
+        :description => "Print the resource in JSON"
+    }
+
+    TOP = {
+        :name => "top",
+        :short => "-t",
+        :large => "--top",
+        :description => "Top for the command"
+    }
+
+    PERIOD = {
+        :name => "period",
+        :short => "-p x",
+        :large => "--period x",
+        :format => Integer,
+        :description => "Seconds between each group of actions"
+    }
+
+    NUMBER = {
+        :name => "number",
+        :short => "-n x",
+        :large => "--number x",
+        :format => Integer,
+        :description => "Number of VMs to apply the action to each period"
+    }
+
+    FORCE = {
+        :name => "force",
+        :short => "-f",
+        :large => "--force",
+        :description => "Force the new cardinality even if it is outside the limits"
+    }
+
+    # Format helpers
+
+#    def self.rname_to_id(name, poolname, options)
+    def self.rname_to_id(name, poolname)
+        return 0, name.to_i if name.match(/^[0123456789]+$/)
+
+        client = Service::Client.new()
+
+        resource_path = case poolname
+        when "SERVICE"          then "/service"
+        when "SERVICE TEMPLATE" then "/service_template"
+        end
+
+        response = client.get(resource_path)
+
+        if CloudClient::is_error?(response)
+            return -1, "OpenNebula #{poolname} name not found," <<
+                       " use the ID instead"
+        end
+
+        pool = JSON.parse(response.body)
+        name_to_id(name, pool, poolname)
+    end
+
+    def self.rname_to_id_desc(poolname)
+        "OpenNebula #{poolname} name or id"
+    end
+
+    def self.name_to_id(name, pool, ename)
+        if pool['DOCUMENT_POOL']['DOCUMENT'].nil?
+            return -1, "#{ename} named #{name} not found."
+        end
+
+        objects = pool['DOCUMENT_POOL']['DOCUMENT'].select {|object| object['NAME'] == name }
+
+        if objects.length>0
+            if objects.length>1
+                return -1, "There are multiple #{ename}s with name #{name}."
+            else
+                result = objects.first['ID']
+            end
+        else
+            return -1, "#{ename} named #{name} not found."
+        end
+
+        return 0, result
+    end
+
+    def self.list_to_id(names, poolname)
+
+        client = Service::Client.new()
+
+        resource_path = case poolname
+        when "SERVICE"          then "/service"
+        when "SERVICE TEMPLATE" then "/service_template"
+        end
+
+        response = client.get(resource_path)
+
+        if CloudClient::is_error?(response)
+            return -1, "OpenNebula #{poolname} name not found," <<
+                       " use the ID instead"
+        end
+
+        pool = JSON.parse(response.body)
+
+        result = names.split(',').collect { |name|
+            if name.match(/^[0123456789]+$/)
+                name.to_i
+            else
+                rc = name_to_id(name, pool, poolname)
+
+                if rc.first == -1
+                    return rc[0], rc[1]
+                end
+
+                rc[1]
+            end
+        }
+
+        return 0, result
+    end
+
+    def self.list_to_id_desc(poolname)
+        "Comma-separated list of OpenNebula #{poolname} names or ids"
+    end
+
+    # Perform an action on several resources
+    # @param [Array] ids resources ids
+    # @param [Block] block action to be performed
+    # @return [Integer] exit_code
+    def self.perform_actions(ids, &block)
+        exit_code = 0
+
+        ids.each do |id|
+            response = block.call(id)
+
+            if CloudClient::is_error?(response)
+                puts response.to_s
+                exit_code = response.code.to_i
+            end
+        end
+
+        exit_code
+    end
+
+    class Client
+        def initialize(opts={})
+            @username = opts[:username] || ENV['ONEFLOW_USER']
+            @password = opts[:password] || ENV['ONEFLOW_PASSWORD']
+
+            url = opts[:url] || ENV['ONEFLOW_URL'] || 'http://localhost:2474'
+
+            if @username.nil? && @password.nil?
+                if ENV["ONE_AUTH"] and !ENV["ONE_AUTH"].empty? and File.file?(ENV["ONE_AUTH"])
+                    one_auth = File.read(ENV["ONE_AUTH"])
+                elsif File.file?(ENV["HOME"]+"/.one/one_auth")
+                    one_auth = File.read(ENV["HOME"]+"/.one/one_auth")
+                end
+
+                one_auth.rstrip!
+
+                @username, @password = one_auth.split(':')
+            end
+
+            @uri = URI.parse(url)
+
+            @user_agent = "OpenNebula #{CloudClient::VERSION} " <<
+                "(#{opts[:user_agent]||"Ruby"})"
+
+            @host = nil
+            @port = nil
+
+            if ENV['http_proxy']
+                uri_proxy  = URI.parse(ENV['http_proxy'])
+                @host = uri_proxy.host
+                @port = uri_proxy.port
+            end
+        end
+
+        def get(path)
+            req = Net::HTTP::Proxy(@host, @port)::Get.new(path)
+
+            do_request(req)
+        end
+
+        def delete(path)
+            req =Net::HTTP::Proxy(@host, @port)::Delete.new(path)
+
+            do_request(req)
+        end
+
+        def post(path, body)
+            req = Net::HTTP::Proxy(@host, @port)::Post.new(path)
+            req.body = body
+
+            do_request(req)
+        end
+
+        def put(path, body)
+            req = Net::HTTP::Proxy(@host, @port)::Put.new(path)
+            req.body = body
+
+            do_request(req)
+        end
+
+        def login
+            req = Net::HTTP::Proxy(@host, @port)::Post.new('/login')
+
+            do_request(req)
+        end
+
+        def logout
+            req = Net::HTTP::Proxy(@host, @port)::Post.new('/logout')
+
+            do_request(req)
+        end
+
+        private
+
+        def do_request(req)
+            req.basic_auth @username, @password
+
+            req['User-Agent'] = @user_agent
+
+            res = CloudClient::http_start(@uri, @timeout) do |http|
+                http.request(req)
+            end
+
+            res
+        end
+    end
+end
\ No newline at end of file
diff --git a/ruby-opennebula-4.4/lib/opennebula/pool.rb b/ruby-opennebula-4.4/lib/opennebula/pool.rb
new file mode 100644 (file)
index 0000000..59b832e
--- /dev/null
@@ -0,0 +1,160 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/xml_utils'
+
+module OpenNebula
+
+    # The Pool class represents a generic OpenNebula Pool in XML format
+    # and provides the basic functionality to handle the Pool elements
+    class Pool < XMLPool
+        include Enumerable
+        alias_method :each_with_xpath, :each
+
+    protected
+        #pool:: _String_ XML name of the root element
+        #element:: _String_ XML name of the Pool elements
+        #client::  _Client_ represents a XML-RPC connection
+        def initialize(pool,element,client)
+            super(nil)
+
+            @pool_name    = pool.upcase
+            @element_name = element.upcase
+
+            @client = client
+        end
+
+        # Default Factory Method for the Pools. The factory method returns an
+        # suitable PoolElement object. Each Pool MUST implement the
+        # corresponding factory method
+        # element_xml:: _XML_ XML element describing the pool element
+        # [return] a PoolElement object
+        def factory(element_xml)
+            OpenNebula::PoolElement.new(element_xml,client)
+        end
+
+        #######################################################################
+        # Common XML-RPC Methods for all the Pool Types
+        #######################################################################
+
+        #Gets the pool without any filter. Host, Group and User Pools
+        # xml_method:: _String_ the name of the XML-RPC method
+        def info(xml_method)
+            return xmlrpc_info(xml_method)
+        end
+
+        alias_method :info!, :info
+
+        def info_all(xml_method, *args)
+            return xmlrpc_info(xml_method,INFO_ALL,-1,-1, *args)
+        end
+
+        def info_mine(xml_method, *args)
+            return xmlrpc_info(xml_method,INFO_MINE,-1,-1, *args)
+        end
+
+        def info_group(xml_method, *args)
+            return xmlrpc_info(xml_method,INFO_GROUP,-1,-1, *args)
+        end
+
+        def info_filter(xml_method, who, start_id, end_id, *args)
+            return xmlrpc_info(xml_method,who, start_id, end_id, *args)
+        end
+
+        # Retrieves the monitoring data for all the Objects in the pool
+        #
+        # @param [String] xml_method xml-rcp method
+        # @param [String] root_elem Root for each individual PoolElement
+        # @param [String] timestamp_elem Name of the XML element with the last
+        #   monitorization timestamp
+        # @param [Array<String>] xpath_expressions Elements to retrieve.
+        # @param args arguemnts for the xml_method call
+        #
+        # @return [Hash<String, <Hash<String, Array<Array<int>>>>>,
+        #   OpenNebula::Error] The first level hash uses the Object ID as keys,
+        #   and as value a Hash with the requested xpath expressions,
+        #   and an Array of 'timestamp, value'.
+        def monitoring(xml_method, root_elem, timestamp_elem, xpath_expressions,
+            *args)
+
+            rc = @client.call(xml_method, *args)
+
+            if ( OpenNebula.is_error?(rc) )
+                return rc
+            end
+
+            xmldoc = XMLElement.new
+            xmldoc.initialize_xml(rc, 'MONITORING_DATA')
+
+            hash = {}
+
+            # Get all existing Object IDs
+            ids = xmldoc.retrieve_elements("#{root_elem}/ID")
+
+            if ids.nil?
+                return hash
+            else
+                ids.uniq!
+            end
+
+            ids.each { |id|
+                hash[id] = OpenNebula.process_monitoring(
+                    xmldoc, root_elem, timestamp_elem, id, xpath_expressions)
+
+            }
+
+            return hash
+        end
+
+    private
+        # Calls to the corresponding info method to retreive the pool
+        # representation in XML format
+        # xml_method:: _String_ the name of the XML-RPC method
+        # args:: _Array_ with additional arguments for the info call
+        # [return] nil in case of success or an Error object
+        def xmlrpc_info(xml_method,*args)
+            rc = @client.call(xml_method,*args)
+
+            if !OpenNebula.is_error?(rc)
+                initialize_xml(rc,@pool_name)
+                rc   = nil
+            end
+
+            return rc
+        end
+
+    public
+        # Constants for info queries (include/RequestManagerPoolInfoFilter.h)
+        INFO_GROUP = -1
+        INFO_ALL   = -2
+        INFO_MINE  = -3
+
+        # Iterates over every PoolElement in the Pool and calls the block with a
+        # a PoolElement obtained calling the factory method
+        # block:: _Block_
+        def each(&block)
+            each_element(block) if @xml
+        end
+
+        # DO NOT USE - ONLY REXML BACKEND
+        def to_str
+            str = ""
+            REXML::Formatters::Pretty.new(1).write(@xml,str)
+
+            return str
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/pool_element.rb b/ruby-opennebula-4.4/lib/opennebula/pool_element.rb
new file mode 100644 (file)
index 0000000..2af930d
--- /dev/null
@@ -0,0 +1,292 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    # The PoolElement Class represents a generic element of a Pool in
+    # XML format
+    class PoolElement < XMLElement
+
+    protected
+        # node:: _XML_is a XML element that represents the Pool element
+        # client:: _Client_ represents a XML-RPC connection
+        def initialize(node, client)
+            @xml    = node
+            @client = client
+
+            if self['ID']
+                @pe_id = self['ID'].to_i
+            else
+                @pe_id = nil
+            end
+            @name = self['NAME'] if self['NAME']
+        end
+
+        #######################################################################
+        # Common XML-RPC Methods for all the Pool Element Types
+        #######################################################################
+
+        # Common client call wrapper. Checks that @pe_id is defined, and
+        # returns nil instead of the response if it is successful
+        #
+        # @param [String] xml_method xml-rpc method
+        # @param [Array] args any arguments for the xml-rpc method
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def call(xml_method, *args)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(xml_method, *args)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Calls to the corresponding info method to retreive the element
+        # detailed information in XML format
+        #
+        # @param [String] xml_method the name of the XML-RPC method
+        # @param [String] root_element Base XML element name
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def info(xml_method, root_element)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(xml_method, @pe_id)
+
+            if !OpenNebula.is_error?(rc)
+                initialize_xml(rc, root_element)
+                rc   = nil
+
+                @pe_id = self['ID'].to_i if self['ID']
+                @name  = self['NAME'] if self['NAME']
+            end
+
+            return rc
+        end
+
+        # Calls to the corresponding allocate method to create a new element
+        # in the OpenNebula core
+        #
+        # @param [String] xml_method the name of the XML-RPC method
+        # @param [Array] args any extra arguments for the xml-rpc method
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def allocate(xml_method, *args)
+            rc = @client.call(xml_method, *args)
+
+            if !OpenNebula.is_error?(rc)
+                @pe_id = rc
+                rc     = nil
+            end
+
+            return rc
+        end
+
+        # Calls to the corresponding update method to modify
+        # the object's template
+        #
+        # @param [String] xml_method the name of the XML-RPC method
+        # @param [String] new_template the new template contents
+        # @param [Array] args any extra arguments for the xml-rpc method
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(xml_method, new_template, *args)
+            new_template ||= template_xml
+
+            return call(xml_method, @pe_id, new_template, *args)
+        end
+
+        # Calls to the corresponding delete method to remove this element
+        # from the OpenNebula core
+        #
+        # @param [String] xml_method the name of the XML-RPC method
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def delete(xml_method)
+            return call(xml_method,@pe_id)
+        end
+
+        # Calls to the corresponding chown method to modify
+        # the object's owner and group
+        #
+        # @param [String] xml_method the name of the XML-RPC method
+        # @param [Integer] uid the new owner id. Set to -1 to leave the current one
+        # @param [Integer] gid the new goup id. Set to -1 to leave the current one
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chown(xml_method, uid, gid)
+            return call(xml_method, @pe_id, uid, gid)
+        end
+
+        # Calls to the corresponding chmod method to modify
+        # the object's permission bits
+        #
+        # @param xml_method [String] the name of the XML-RPC method
+        # @param octet [String] Permissions octed , e.g. 640
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod_octet(xml_method, octet)
+            owner_u = octet[0..0].to_i & 4 != 0 ? 1 : 0
+            owner_m = octet[0..0].to_i & 2 != 0 ? 1 : 0
+            owner_a = octet[0..0].to_i & 1 != 0 ? 1 : 0
+            group_u = octet[1..1].to_i & 4 != 0 ? 1 : 0
+            group_m = octet[1..1].to_i & 2 != 0 ? 1 : 0
+            group_a = octet[1..1].to_i & 1 != 0 ? 1 : 0
+            other_u = octet[2..2].to_i & 4 != 0 ? 1 : 0
+            other_m = octet[2..2].to_i & 2 != 0 ? 1 : 0
+            other_a = octet[2..2].to_i & 1 != 0 ? 1 : 0
+
+            chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
+                other_m, other_a)
+        end
+
+        # Calls to the corresponding chmod method to modify
+        # the object's permission bits
+        # Each [Integer] parameter must be 1 to allow, 0 deny, -1 do not change
+        #
+        # @param xml_method [String] the name of the XML-RPC method
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod(xml_method, owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
+                other_m, other_a)
+            return call(xml_method, @pe_id, owner_u, owner_m,
+                            owner_a, group_u, group_m, group_a, other_u,
+                            other_m, other_a)
+        end
+
+
+        # Retrieves this Element's monitoring data from OpenNebula
+        #
+        # @param [String] xml_method the name of the XML-RPC method
+        # @param [String] root_elem Root for each individual PoolElement
+        # @param [String] timestamp_elem Name of the XML element with the last
+        #   monitorization timestamp
+        # @param xpath_expressions [Array<String>] Xpath expressions for the
+        #   elements to retrieve.
+        #
+        # @return [Hash<String, Array<Array<int>>, OpenNebula::Error] Hash with
+        #   the requested xpath expressions, and an Array of [timestamp, value].
+        def monitoring(xml_method, root_elem, timestamp_elem, xpath_expressions)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(xml_method, @pe_id)
+
+            if ( OpenNebula.is_error?(rc) )
+                return rc
+            end
+
+            xmldoc = XMLElement.new
+            xmldoc.initialize_xml(rc, 'MONITORING_DATA')
+
+
+            return OpenNebula.process_monitoring(
+                xmldoc, root_elem, timestamp_elem, @pe_id, xpath_expressions)
+        end
+
+    public
+
+        # Creates new element specifying its id
+        # id:: identifyier of the element
+        # client:: initialized OpenNebula::Client object
+        def self.new_with_id(id, client=nil)
+            self.new(self.build_xml(id), client)
+        end
+
+        # Returns element identifier
+        # [return] _Integer_ the PoolElement ID
+        def id
+            @pe_id
+        end
+
+        # Gets element name
+        # [return] _String_ the PoolElement name
+        def name
+            @name
+        end
+
+        # DO NOT USE - ONLY REXML BACKEND
+        def to_str
+            str = ""
+            REXML::Formatters::Pretty.new(1).write(@xml,str)
+
+            return str
+        end
+    end
+
+    # Processes the monitoring data in XML returned by OpenNebula
+    #
+    # @param [XMLElement] xmldoc monitoring data returned by OpenNebula
+    # @param [String] root_elem Root for each individual PoolElement
+    # @param [String] timestamp_elem Name of the XML element with the last
+    #   monitorization timestamp
+    # @param [Integer] oid Id of the object to process
+    # @param [Array<String>] xpath_expressions Elements to retrieve.
+    #
+    # @return [Hash<String, Array<Array<int>>, OpenNebula::Error] Hash with
+    #   the requested xpath expressions, and an Array of [timestamp, value].
+    def self.process_monitoring(xmldoc, root_elem, timestamp_elem, oid, xpath_expressions)
+        hash = {}
+        timestamps = xmldoc.retrieve_elements(
+            "#{root_elem}[ID=#{oid}]/#{timestamp_elem}")
+
+        xpath_expressions.each { |xpath|
+            xpath_values = xmldoc.retrieve_elements("#{root_elem}[ID=#{oid}]/#{xpath}")
+
+            if ( xpath_values.nil? )
+                hash[xpath] = []
+            else
+                hash[xpath] = timestamps.zip(xpath_values)
+            end
+        }
+
+        return hash
+    end
+
+
+    # Alternative method with better performance for huge number of timestamps.
+    # For reasonable amounts of data, the current method is quicker
+=begin
+    def self.process_monitoring(xmldoc, root_elem, timestamp_elem, oid, xpath_expressions)
+        hash = {}
+
+        xpath_expressions.each { |xpath|
+            hash[xpath] = []
+        }
+
+        xmldoc.each("#{root_elem}[ID=#{oid}]") do |elem|
+            timestamp = elem[timestamp_elem]
+
+            xpath_expressions.each { |xpath|
+                xpath_value = elem[xpath]
+
+                hash[xpath] << [timestamp, xpath_value] if !xpath_value.nil?
+            }
+        end
+
+        return hash
+    end
+=end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/server_cipher_auth.rb b/ruby-opennebula-4.4/lib/opennebula/server_cipher_auth.rb
new file mode 100644 (file)
index 0000000..78476ef
--- /dev/null
@@ -0,0 +1,148 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'openssl'
+require 'digest/sha1'
+
+require 'base64'
+require 'fileutils'
+
+module OpenNebula; end
+
+# Server authentication class. This method can be used by OpenNebula services
+# to let access authenticated users by other means. It is based on OpenSSL 
+# symmetric ciphers
+class OpenNebula::ServerCipherAuth 
+    ###########################################################################
+    #Constants with paths to relevant files and defaults
+    ###########################################################################
+
+    CIPHER = "aes-256-cbc"
+
+    ###########################################################################
+
+    def initialize(srv_user, srv_passwd)
+        @srv_user   = srv_user
+        @srv_passwd = srv_passwd 
+
+        if !srv_passwd.empty?
+            @key = Digest::SHA1.hexdigest(@srv_passwd)
+        else
+            @key = ""
+        end
+
+        @cipher = OpenSSL::Cipher::Cipher.new(CIPHER)
+    end
+
+    ###########################################################################
+    # Client side
+    ###########################################################################
+
+    # Creates a ServerCipher for client usage
+    def self.new_client(srv_user=nil, srv_passwd=nil)
+        if ( srv_user == nil || srv_passwd == nil ) 
+            begin
+                if ENV["ONE_CIPHER_AUTH"] and !ENV["ONE_CIPHER_AUTH"].empty?
+                    one_auth = File.read(ENV["ONE_CIPHER_AUTH"])
+                else
+                    raise "ONE_CIPHER_AUTH environment variable not set"
+                end
+
+                one_auth.rstrip!
+
+                rc =  one_auth.match(/(.*?):(.*)/)
+                
+                if rc.nil?
+                    raise "Bad format for one_auth token (<user>:<passwd>)"
+                else 
+                    srv_user   = rc[1]
+                    srv_passwd = rc[2]
+                end
+            rescue => e
+                raise e.message
+            end
+        end 
+
+        self.new(srv_user, srv_passwd)
+    end
+
+    # Generates a login token in the form:
+    #   - server_user:target_user:time_expires 
+    # The token is then encrypted with the contents of one_auth
+    def login_token(expire, target_user=nil)
+        target_user ||= @srv_user
+        token_txt   =   "#{@srv_user}:#{target_user}:#{expire}"
+
+        token   = encrypt(token_txt)
+        token64 = Base64::encode64(token).strip.delete("\n")
+
+        return "#{@srv_user}:#{target_user}:#{token64}"
+    end
+
+    # Returns a valid password string to create a user using this auth driver
+    def password
+        return @srv_passwd
+    end
+
+    ###########################################################################
+    # Driver side
+    ###########################################################################
+
+    # Creates a ServerCipher for driver usage
+    def self.new_driver()
+        self.new("","")
+    end
+
+    # auth method for auth_mad
+    def authenticate(srv_user,srv_pass, signed_text)
+        begin
+            @key = srv_pass
+            
+            s_user, t_user, expires = decrypt(signed_text).split(':')
+
+            return "User name missmatch" if s_user != srv_user
+             
+            return "login token expired" if Time.now.to_i >= expires.to_i
+
+            return true
+        rescue => e
+            return e.message
+        end
+    end
+
+    private
+
+    def encrypt(data) 
+        @cipher.encrypt
+        @cipher.key = @key
+        
+        rc = @cipher.update(data)
+        rc << @cipher.final
+
+        return rc
+    end
+
+    def decrypt(data) 
+        @cipher.decrypt
+        @cipher.key = @key
+        
+        rc = @cipher.update(Base64::decode64(data))
+        rc << @cipher.final
+
+        return rc
+    end
+end
+
diff --git a/ruby-opennebula-4.4/lib/opennebula/server_x509_auth.rb b/ruby-opennebula-4.4/lib/opennebula/server_x509_auth.rb
new file mode 100644 (file)
index 0000000..6799e43
--- /dev/null
@@ -0,0 +1,104 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'openssl'
+require 'base64'
+require 'fileutils'
+
+require 'opennebula/x509_auth'
+
+module OpenNebula; end
+
+# Server authentication class. This authmethod can be used by opennebula services
+# to let access authenticated users by other means. It is based on x509 server
+# certificates
+class OpenNebula::ServerX509Auth < OpenNebula::X509Auth
+    ###########################################################################
+    #Constants with paths to relevant files and defaults
+    ###########################################################################
+
+    SERVER_AUTH_CONF_PATH = ETC_LOCATION + "/auth/server_x509_auth.conf"
+
+    SERVER_DEFAULTS = {
+        :one_cert => ETC_LOCATION + "/auth/cert.pem",
+        :one_key  => ETC_LOCATION + "/auth/key.pem"
+    }
+
+    ###########################################################################
+
+    def initialize()
+        @options = SERVER_DEFAULTS
+
+        load_options(SERVER_AUTH_CONF_PATH)
+
+        begin
+            certs = [ File.read(@options[:one_cert]) ]
+            key   =   File.read(@options[:one_key])
+
+            super(:certs_pem => certs, :key_pem => key)
+        rescue
+            raise
+        end
+
+        if @options[:srv_user] == nil || @options[:srv_user].empty?
+           raise "User for x509 server not defined"
+        end
+    end
+
+    ###########################################################################
+    # Client side
+    ###########################################################################
+
+    # Creates a ServerCipher for client and driver sage
+    class << OpenNebula::ServerX509Auth
+        alias :new_client :new
+        alias :new_driver :new
+    end
+
+    # Generates a login token in the form:
+    #   - server_user:target_user:time_expires
+    def login_token(expire, target_user=nil)
+        target_user ||= @options[:srv_user]
+        token_txt   =   "#{@options[:srv_user]}:#{target_user}:#{expire}"
+
+        token   = encrypt(token_txt)
+        token64 = Base64::encode64(token).strip.delete("\n")
+
+        return "#{@options[:srv_user]}:#{target_user}:#{token64}"
+    end
+
+    ###########################################################################
+    # Server side
+    ###########################################################################
+
+    # auth method for auth_mad
+    def authenticate(server_user, server_pass, signed_text)
+        begin
+            s_user, t_user, expires = decrypt(signed_text).split(':')
+
+            return "Server password missmatch" if server_pass != password
+
+            return "User name missmatch" if ( s_user != server_user ||
+                                              s_user != @options[:srv_user] )
+
+            return "login token expired" if Time.now.to_i >= expires.to_i
+
+            return true
+        rescue => e
+            return e.message
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/ssh_auth.rb b/ruby-opennebula-4.4/lib/opennebula/ssh_auth.rb
new file mode 100644 (file)
index 0000000..db06978
--- /dev/null
@@ -0,0 +1,141 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'pp'
+require 'openssl'
+require 'base64'
+require 'fileutils'
+
+module OpenNebula; end
+
+# SSH key authentication class. It can be used as a driver for auth_mad
+# as auth method is defined. It also holds some helper methods to be used
+# by oneauth command
+class OpenNebula::SshAuth
+    LOGIN_PATH = ENV['HOME']+'/.one/one_ssh'
+
+    # Initialize SshAuth object
+    #
+    # @param [Hash] default options for path
+    # @option options [String] :public_key public key for the user
+    # @option options [String] :private_key key private key for the user.
+    def initialize(options={})
+        @private_key = nil
+        @public_key  = nil
+
+        # Initialize the private key
+        if options[:private_key]
+            begin
+                @private_key = File.read(options[:private_key])
+            rescue Exception => e
+                raise "Cannot read #{options[:private_key]}"
+            end
+
+            @private_key_rsa = OpenSSL::PKey::RSA.new(@private_key)
+        end
+
+        # Initialize the public key
+        if options[:public_key]
+            @public_key = options[:public_key]
+        elsif @private_key != nil
+            # Init ssh keys using private key. public key is extracted in a
+            # format compatible with openssl. The public key does not contain
+            # "---- BEGIN/END PUBLIC KEY ----" and is in a single line
+            @public_key = @private_key_rsa.public_key.to_pem.split("\n")
+            @public_key = @public_key.reject {|l| l.match(/PUBLIC KEY/) }.join('')
+        end
+
+        if @private_key.nil? && @public_key.nil?
+            raise "You have to define at least one of the keys"
+        end
+
+        @public_key_rsa = OpenSSL::PKey::RSA.new(Base64::decode64(@public_key))
+    end
+
+    # Creates the login file for ssh authentication at ~/.one/one_ssh.
+    # By default it is valid for 1 hour but it can be changed to any number
+    # of seconds with expire parameter (in seconds)
+    def login(user, expire=3600)
+        expire ||= 3600
+
+        # Init proxy file path and creates ~/.one directory if needed
+        proxy_dir = File.dirname(LOGIN_PATH)
+
+        begin
+            FileUtils.mkdir_p(proxy_dir)
+        rescue Errno::EEXIST
+        end
+
+        # Generate security token
+        time = Time.now.to_i + expire.to_i
+
+        secret_plain   = "#{user}:#{time}"
+        secret_crypted = encrypt(secret_plain)
+
+        proxy = "#{user}:#{secret_crypted}"
+
+        file = File.open(LOGIN_PATH, "w")
+        file.write(proxy)
+        file.close
+
+        File.chmod(0600,LOGIN_PATH)
+
+        secret_crypted
+    end
+
+    # Returns a valid password string to create a user using this auth driver.
+    # In this case the ssh public key.
+    def password
+        @public_key
+    end
+
+    # Checks the proxy created with the login method
+    def authenticate(user, token)
+        begin
+            token_plain = decrypt(token)
+            _user, time = token_plain.split(':')
+
+            if user == _user
+                if Time.now.to_i >= time.to_i
+                    return "ssh proxy expired, login again to renew it"
+                else
+                    return true
+                end
+            else
+                return "invalid credentials"
+            end
+        rescue
+            return "error"
+        end
+    end
+
+    private
+
+    ###########################################################################
+    #                       Methods to handle ssh keys
+    ###########################################################################
+    # Encrypts data with the private key of the user and returns
+    # base 64 encoded output in a single line
+    def encrypt(data)
+        Base64::encode64(@private_key_rsa.private_encrypt(data)).gsub!(/\n/, '').strip
+    end
+
+    # Decrypts base 64 encoded data with pub_key (public key)
+    def decrypt(data)
+        @public_key_rsa.public_decrypt(Base64::decode64(data))
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/system.rb b/ruby-opennebula-4.4/lib/opennebula/system.rb
new file mode 100644 (file)
index 0000000..ab3eae4
--- /dev/null
@@ -0,0 +1,141 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class System
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+        SYSTEM_METHODS = {
+            :userquotainfo      => "userquota.info",
+            :userquotaupdate    => "userquota.update",
+            :groupquotainfo     => "groupquota.info",
+            :groupquotaupdate   => "groupquota.update",
+            :version            => "system.version",
+            :config             => "system.config"
+        }
+
+        #######################################################################
+        # Class constructor
+        #######################################################################
+
+        # Constructor
+        #   @param [Client] client that represents a XML-RPC connection
+        def initialize(client)
+            @client = client
+        end
+
+        #######################################################################
+        # XML-RPC Methods
+        #######################################################################
+
+        # Gets the oned version
+        #
+        # @return [String, OpenNebula::Error] the oned version in case
+        #   of success, Error otherwise
+        def get_oned_version()
+            return @client.call("system.version")
+        end
+
+        # Returns whether of not the oned version is the same as the OCA version
+        #
+        # @return [true, false, OpenNebula::Error] true if oned is the same
+        #   version
+        def compatible_version()
+            no_revision = VERSION[/^\d+\.\d+\./]
+            oned_v = get_oned_version
+
+            if OpenNebula.is_error?(oned_v)
+                return oned_v
+            end
+
+            return (oned_v =~ /#{no_revision}/) != nil
+        end
+
+        # Gets the oned configuration
+        #
+        # @return [XMLElement, OpenNebula::Error] the oned configuration in case
+        #   of success, Error otherwise
+        def get_configuration()
+            rc = @client.call(SYSTEM_METHODS[:config])
+
+            if OpenNebula.is_error?(rc)
+                return rc
+            end
+
+            config = XMLElement.new
+            config.initialize_xml(rc, 'TEMPLATE')
+
+            return config
+        end
+
+        # Gets the default user quota limits
+        #
+        # @return [XMLElement, OpenNebula::Error] the default user quota in case
+        #   of success, Error otherwise
+        def get_user_quotas()
+            rc = @client.call(SYSTEM_METHODS[:userquotainfo])
+
+            if OpenNebula.is_error?(rc)
+                return rc
+            end
+
+            default_quotas = XMLElement.new
+            default_quotas.initialize_xml(rc, 'DEFAULT_USER_QUOTAS')
+
+            return default_quotas
+        end
+
+        # Sets the default user quota limits
+        # @param quota [String] a template (XML or txt) with the new quota limits
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def set_user_quotas(quota)
+            return @client.call(SYSTEM_METHODS[:userquotaupdate], quota)
+        end
+
+        # Gets the default group quota limits
+        #
+        # @return [XMLElement, OpenNebula::Error] the default group quota in case
+        #   of success, Error otherwise
+        def get_group_quotas()
+            rc = @client.call(SYSTEM_METHODS[:groupquotainfo])
+
+            if OpenNebula.is_error?(rc)
+                return rc
+            end
+
+            default_quotas = XMLElement.new
+            default_quotas.initialize_xml(rc, 'DEFAULT_GROUP_QUOTAS')
+
+            return default_quotas
+        end
+
+        # Sets the default group quota limits
+        # @param quota [String] a template (XML or txt) with the new quota limits
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def set_group_quotas(quota)
+            return @client.call(SYSTEM_METHODS[:groupquotaupdate], quota)
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/template.rb b/ruby-opennebula-4.4/lib/opennebula/template.rb
new file mode 100644 (file)
index 0000000..91d92c0
--- /dev/null
@@ -0,0 +1,216 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+
+module OpenNebula
+    class Template < PoolElement
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+
+        TEMPLATE_METHODS = {
+            :allocate    => "template.allocate",
+            :instantiate => "template.instantiate",
+            :info        => "template.info",
+            :update      => "template.update",
+            :delete      => "template.delete",
+            :chown       => "template.chown",
+            :chmod       => "template.chmod",
+            :clone       => "template.clone",
+            :rename      => "template.rename"
+        }
+
+        # Creates a Template description with just its identifier
+        # this method should be used to create plain Template objects.
+        # +id+ the id of the user
+        #
+        # Example:
+        #   template = Template.new(Template.build_xml(3),rpc_client)
+        #
+        def Template.build_xml(pe_id=nil)
+            if pe_id
+                obj_xml = "<VMTEMPLATE><ID>#{pe_id}</ID></VMTEMPLATE>"
+            else
+                obj_xml = "<VMTEMPLATE></VMTEMPLATE>"
+            end
+
+            XMLElement.build_xml(obj_xml,'VMTEMPLATE')
+        end
+
+        # Class constructor
+        def initialize(xml, client)
+            super(xml,client)
+
+            @client = client
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Template Object
+        #######################################################################
+
+        # Retrieves the information of the given Template.
+        def info()
+            super(TEMPLATE_METHODS[:info], 'VMTEMPLATE')
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new Template in OpenNebula
+        #
+        # @param description [String] The contents of the Template.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def allocate(description)
+            super(TEMPLATE_METHODS[:allocate], description)
+        end
+
+        # Deletes the Template
+        def delete()
+            super(TEMPLATE_METHODS[:delete])
+        end
+
+        # Creates a VM instance from a Template
+        #
+        # @param name [String] Name for the VM instance. If it is an empty
+        #   string OpenNebula will set a default name
+        # @param hold [true,false] false to create the VM in pending state,
+        #   true to create it on hold
+        # @param template [String] User provided Template to merge with the
+        #   one being instantiated
+        #
+        # @return [Integer, OpenNebula::Error] The new VM id, Error
+        #   otherwise
+        def instantiate(name="", hold=false, template="")
+            return Error.new('ID not defined') if !@pe_id
+
+            name ||= ""
+            template ||= ""
+
+            rc = @client.call(
+                TEMPLATE_METHODS[:instantiate], @pe_id, name, hold, template)
+
+            return rc
+        end
+
+        # Replaces the template contents
+        #
+        # @param new_template [String] New template contents
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(new_template, append=false)
+            super(TEMPLATE_METHODS[:update], new_template, append ? 1 : 0)
+        end
+
+        # Publishes the Template, to be used by other users
+        def publish
+            set_publish(true)
+        end
+
+        # Unplubishes the Image
+        def unpublish
+            set_publish(false)
+        end
+
+        # Changes the owner/group
+        # uid:: _Integer_ the new owner id. Set to -1 to leave the current one
+        # gid:: _Integer_ the new group id. Set to -1 to leave the current one
+        # [return] nil in case of success or an Error object
+        def chown(uid, gid)
+            super(TEMPLATE_METHODS[:chown], uid, gid)
+        end
+
+        # Changes the Template permissions.
+        #
+        # @param octet [String] Permissions octed , e.g. 640
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod_octet(octet)
+            super(TEMPLATE_METHODS[:chmod], octet)
+        end
+
+        # Changes the Template permissions.
+        # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
+                other_m, other_a)
+            super(TEMPLATE_METHODS[:chmod], owner_u, owner_m, owner_a, group_u,
+                group_m, group_a, other_u, other_m, other_a)
+        end
+
+        # Clones this Template into a new one
+        #
+        # @param [String] name for the new Template.
+        #
+        # @return [Integer, OpenNebula::Error] The new Template ID in case
+        #   of success, Error otherwise
+        def clone(name)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(TEMPLATE_METHODS[:clone], @pe_id, name)
+
+            return rc
+        end
+
+        # Renames this Template
+        #
+        # @param name [String] New name for the Template.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def rename(name)
+            return call(TEMPLATE_METHODS[:rename], @pe_id, name)
+        end
+
+        #######################################################################
+        # Helpers to get Template information
+        #######################################################################
+
+        # Returns the group identifier
+        # [return] _Integer_ the element's group ID
+        def gid
+            self['GID'].to_i
+        end
+
+        def owner_id
+            self['UID'].to_i
+        end
+
+        def public?
+            if self['PERMISSIONS/GROUP_U'] == "1" || self['PERMISSIONS/OTHER_U'] == "1"
+                true
+            else
+                false
+            end
+        end
+
+    private
+
+        def set_publish(published)
+            group_u = published ? 1 : 0
+
+            chmod(-1, -1, -1, group_u, -1, -1, -1, -1, -1)
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/template_pool.rb b/ruby-opennebula-4.4/lib/opennebula/template_pool.rb
new file mode 100644 (file)
index 0000000..10bfd93
--- /dev/null
@@ -0,0 +1,79 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class TemplatePool < Pool
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+
+        TEMPLATE_POOL_METHODS = {
+            :info => "templatepool.info"
+        }
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+        # +client+ a Client object that represents an XML-RPC connection
+        # +user_id+ used to refer to a Pool with Templates from that user
+        def initialize(client, user_id=-1)
+            super('VMTEMPLATE_POOL','VMTEMPLATE',client)
+
+            @user_id  = user_id
+        end
+
+        # Factory method to create Template objects
+        def factory(element_xml)
+            OpenNebula::Template.new(element_xml,@client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Template Object
+        #######################################################################
+
+        # Retrieves all or part of the VirtualMachines in the pool.
+        def info(*args)
+            case args.size
+                when 0
+                    info_filter(TEMPLATE_POOL_METHODS[:info],@user_id,-1,-1)
+                when 3
+                    info_filter(TEMPLATE_POOL_METHODS[:info],args[0],args[1],args[2])
+            end
+        end
+
+        def info_all()
+            return super(TEMPLATE_POOL_METHODS[:info])
+        end
+
+        def info_mine()
+            return super(TEMPLATE_POOL_METHODS[:info])
+        end
+
+        def info_group()
+            return super(TEMPLATE_POOL_METHODS[:info])
+        end
+
+        alias_method :info!, :info
+        alias_method :info_all!, :info_all
+        alias_method :info_mine!, :info_mine
+        alias_method :info_group!, :info_group
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/user.rb b/ruby-opennebula-4.4/lib/opennebula/user.rb
new file mode 100644 (file)
index 0000000..4548ae5
--- /dev/null
@@ -0,0 +1,198 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+
+module OpenNebula
+    class User < PoolElement
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+        USER_METHODS = {
+            :info     => "user.info",
+            :allocate => "user.allocate",
+            :delete   => "user.delete",
+            :passwd   => "user.passwd",
+            :chgrp    => "user.chgrp",
+            :addgroup => "user.addgroup",
+            :delgroup => "user.delgroup",
+            :update   => "user.update",
+            :chauth   => "user.chauth",
+            :quota    => "user.quota"
+        }
+
+        SELF      = -1
+
+        # Driver name for default core authentication
+        CORE_AUTH = "core"
+
+        # Driver name for default core authentication
+        CIPHER_AUTH = "server_cipher"
+
+        # Driver name for ssh authentication
+        SSH_AUTH  = "ssh"
+
+        # Driver name for x509 authentication
+        X509_AUTH = "x509"
+
+        # Driver name for x509 proxy authentication
+        X509_PROXY_AUTH = "x509_proxy"
+
+        # Creates a User description with just its identifier
+        # this method should be used to create plain User objects.
+        # +id+ the id of the user
+        #
+        # Example:
+        #   user = User.new(User.build_xml(3),rpc_client)
+        #
+        def User.build_xml(pe_id=nil)
+            if pe_id
+                user_xml = "<USER><ID>#{pe_id}</ID></USER>"
+            else
+                user_xml = "<USER></USER>"
+            end
+
+            XMLElement.build_xml(user_xml, 'USER')
+        end
+
+        # Class constructor
+        def initialize(xml, client)
+            super(xml,client)
+
+            @client = client
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the User Object
+        #######################################################################
+
+        # Retrieves the information of the given User.
+        def info()
+            super(USER_METHODS[:info], 'USER')
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new User in OpenNebula
+        #
+        # +username+ Name of the new user.
+        #
+        # +password+ Password for the new user
+        def allocate(username, password, driver=CORE_AUTH)
+            super(USER_METHODS[:allocate], username, password, driver)
+        end
+
+        # Replaces the template contents
+        #
+        # @param new_template [String] New template contents
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(new_template, append=false)
+            super(USER_METHODS[:update], new_template, append ? 1 : 0)
+        end
+
+        # Deletes the User
+        def delete()
+            super(USER_METHODS[:delete])
+        end
+
+        # Changes the password of the given User
+        #
+        # +password+ String containing the new password
+        def passwd(password)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(USER_METHODS[:passwd], @pe_id, password)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Changes the primary group
+        # gid:: _Integer_ the new group id. Set to -1 to leave the current one
+        # [return] nil in case of success or an Error object
+        def chgrp(gid)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(USER_METHODS[:chgrp],@pe_id, gid)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Adds the User to a secondary group
+        # @param gid [Integer] the new group id.
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def addgroup(gid)
+            return call(USER_METHODS[:addgroup], @pe_id, gid)
+        end
+
+        # Removes the User from a secondary group. Fails if the
+        # group is the main one
+        # @param gid [Integer] the group id.
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def delgroup(gid)
+            return call(USER_METHODS[:delgroup], @pe_id, gid)
+        end
+
+        # Changes the auth driver and the password of the given User
+        #
+        # @param auth [String] the new auth driver
+        # @param password [String] the new password. If it is an empty string,
+        #   the user password is not changed
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chauth(auth, password="")
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(USER_METHODS[:chauth],@pe_id, auth, password)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Sets the user quota limits
+        # @param quota [String] a template (XML or txt) with the new quota limits 
+        # 
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def set_quota(quota)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(USER_METHODS[:quota],@pe_id, quota)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        #######################################################################
+        # Helpers to get User information
+        #######################################################################
+
+        # Returns the group identifier
+        # [return] _Integer_ the element's group ID
+        def gid
+            self['GID'].to_i
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/user_pool.rb b/ruby-opennebula-4.4/lib/opennebula/user_pool.rb
new file mode 100644 (file)
index 0000000..6e87507
--- /dev/null
@@ -0,0 +1,55 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class UserPool < Pool
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+        USER_POOL_METHODS = {
+            :info => "userpool.info"
+        }
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+        # +client+ a Client object that represents a XML-RPC connection
+        def initialize(client)
+            super('USER_POOL','USER',client)
+        end
+
+        # Factory method to create User objects
+        def factory(element_xml)
+            OpenNebula::User.new(element_xml,@client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the User Object
+        #######################################################################
+
+        # Retrieves all the Users in the pool.
+        def info()
+            super(USER_POOL_METHODS[:info])
+        end
+
+        alias_method :info!, :info
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/virtual_machine.rb b/ruby-opennebula-4.4/lib/opennebula/virtual_machine.rb
new file mode 100644 (file)
index 0000000..5a60c20
--- /dev/null
@@ -0,0 +1,597 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+
+module OpenNebula
+    class VirtualMachine < PoolElement
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+        VM_METHODS = {
+            :info       => "vm.info",
+            :allocate   => "vm.allocate",
+            :action     => "vm.action",
+            :migrate    => "vm.migrate",
+            :deploy     => "vm.deploy",
+            :savedisk   => "vm.savedisk",
+            :chown      => "vm.chown",
+            :chmod      => "vm.chmod",
+            :monitoring => "vm.monitoring",
+            :attach     => "vm.attach",
+            :detach     => "vm.detach",
+            :rename     => "vm.rename",
+            :update     => "vm.update",
+            :resize     => "vm.resize",
+            :snapshotcreate => "vm.snapshotcreate",
+            :snapshotrevert => "vm.snapshotrevert",
+            :snapshotdelete => "vm.snapshotdelete",
+            :attachnic  => "vm.attachnic",
+            :detachnic  => "vm.detachnic",
+            :resize     => "vm.resize",
+            :recover    => "vm.recover"
+        }
+
+        VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED
+            POWEROFF UNDEPLOYED}
+
+        LCM_STATE=%w{LCM_INIT PROLOG BOOT RUNNING MIGRATE SAVE_STOP SAVE_SUSPEND
+            SAVE_MIGRATE PROLOG_MIGRATE PROLOG_RESUME EPILOG_STOP EPILOG
+            SHUTDOWN CANCEL FAILURE CLEANUP_RESUBMIT UNKNOWN HOTPLUG SHUTDOWN_POWEROFF
+            BOOT_UNKNOWN BOOT_POWEROFF BOOT_SUSPENDED BOOT_STOPPED CLEANUP_DELETE
+            HOTPLUG_SNAPSHOT HOTPLUG_NIC HOTPLUG_SAVEAS HOTPLUG_SAVEAS_POWEROFF
+            HOTPLUG_SAVEAS_SUSPENDED SHUTDOWN_UNDEPLOY EPILOG_UNDEPLOY
+            PROLOG_UNDEPLOY BOOT_UNDEPLOY}
+
+        SHORT_VM_STATES={
+            "INIT"      => "init",
+            "PENDING"   => "pend",
+            "HOLD"      => "hold",
+            "ACTIVE"    => "actv",
+            "STOPPED"   => "stop",
+            "SUSPENDED" => "susp",
+            "DONE"      => "done",
+            "FAILED"    => "fail",
+            "POWEROFF"  => "poff",
+            "UNDEPLOYED"=> "unde"
+        }
+
+        SHORT_LCM_STATES={
+            "PROLOG"            => "prol",
+            "BOOT"              => "boot",
+            "RUNNING"           => "runn",
+            "MIGRATE"           => "migr",
+            "SAVE_STOP"         => "save",
+            "SAVE_SUSPEND"      => "save",
+            "SAVE_MIGRATE"      => "save",
+            "PROLOG_MIGRATE"    => "migr",
+            "PROLOG_RESUME"     => "prol",
+            "EPILOG_STOP"       => "epil",
+            "EPILOG"            => "epil",
+            "SHUTDOWN"          => "shut",
+            "CANCEL"            => "shut",
+            "FAILURE"           => "fail",
+            "CLEANUP_RESUBMIT"  => "clea",
+            "UNKNOWN"           => "unkn",
+            "HOTPLUG"           => "hotp",
+            "SHUTDOWN_POWEROFF" => "shut",
+            "BOOT_UNKNOWN"      => "boot",
+            "BOOT_POWEROFF"     => "boot",
+            "BOOT_SUSPENDED"    => "boot",
+            "BOOT_STOPPED"      => "boot",
+            "CLEANUP_DELETE"    => "clea",
+            "HOTPLUG_SNAPSHOT"  => "snap",
+            "HOTPLUG_NIC"       => "hotp",
+            "HOTPLUG_SAVEAS"           => "hotp",
+            "HOTPLUG_SAVEAS_POWEROFF"  => "hotp",
+            "HOTPLUG_SAVEAS_SUSPENDED" => "hotp",
+            "SHUTDOWN_UNDEPLOY" => "shut",
+            "EPILOG_UNDEPLOY"   => "epil",
+            "PROLOG_UNDEPLOY"   => "prol",
+            "BOOT_UNDEPLOY"     => "boot"
+        }
+
+        MIGRATE_REASON=%w{NONE ERROR USER}
+
+        SHORT_MIGRATE_REASON={
+            "NONE"          => "none",
+            "ERROR"         => "erro",
+            "USER"          => "user"
+        }
+
+        HISTORY_ACTION=%w{none migrate live-migrate shutdown shutdown-hard
+            undeploy undeploy-hard hold release stop suspend resume boot delete
+            delete-recreate reboot reboot-hard resched unresched poweroff
+            poweroff-hard}
+
+        # Creates a VirtualMachine description with just its identifier
+        # this method should be used to create plain VirtualMachine objects.
+        # +id+ the id of the vm
+        #
+        # Example:
+        #   vnet = VirtualMachine.new(VirtualMachine.build_xml(3),rpc_client)
+        #
+        def VirtualMachine.build_xml(pe_id=nil)
+            if pe_id
+                vm_xml = "<VM><ID>#{pe_id}</ID></VM>"
+            else
+                vm_xml = "<VM></VM>"
+            end
+
+            XMLElement.build_xml(vm_xml, 'VM')
+        end
+
+        def VirtualMachine.get_reason(reason)
+            reason=MIGRATE_REASON[reason.to_i]
+            reason_str=SHORT_MIGRATE_REASON[reason]
+
+            reason_str
+        end
+
+        def VirtualMachine.get_history_action(action)
+            return HISTORY_ACTION[action.to_i]
+        end
+
+        # Class constructor
+        def initialize(xml, client)
+            super(xml,client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Virtual Machine Object
+        #######################################################################
+
+        # Retrieves the information of the given VirtualMachine.
+        def info()
+            super(VM_METHODS[:info], 'VM')
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new VirtualMachine in OpenNebula
+        #
+        # @param description [String] A string containing the template of
+        #   the VirtualMachine.
+        # @param hold [true,false] false to create the VM in pending state,
+        #   true to create it on hold
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def allocate(description, hold=false)
+            super(VM_METHODS[:allocate], description, hold)
+        end
+
+        # Replaces the template contents
+        #
+        # @param new_template [String] New template contents
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(new_template=nil, append=false)
+            super(VM_METHODS[:update], new_template, append ? 1 : 0)
+        end
+
+        # Returns the <USER_TEMPLATE> element in text form
+        #
+        # @param indent [true,false] indents the resulting string, defaults to true
+        #
+        # @return [String] The USER_TEMPLATE
+        def user_template_str(indent=true)
+            template_like_str('USER_TEMPLATE', indent)
+        end
+
+        # Returns the <USER_TEMPLATE> element in XML form
+        #
+        # @return [String] The USER_TEMPLATE
+        def user_template_xml
+            if NOKOGIRI
+                @xml.xpath('TEMPLATE').to_s
+            else
+                @xml.elements['TEMPLATE'].to_s
+            end
+        end
+
+
+        # Initiates the instance of the VM on the target host.
+        #
+        # @param host_id [Interger] The host id (hid) of the target host where
+        #   the VM will be instantiated.
+        # @param enforce [true|false] If it is set to true, the host capacity
+        #   will be checked, and the deployment will fail if the host is
+        #   overcommited. Defaults to false
+        # @param ds_id [Integer] The System Datastore where to deploy the VM. To
+        #   use the default, set it to -1
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def deploy(host_id, enforce=false, ds_id=-1)
+            enforce ||= false
+            ds_id ||= -1
+            return call(VM_METHODS[:deploy], @pe_id, host_id.to_i, enforce, ds_id.to_i)
+        end
+
+        # Shutdowns an already deployed VM
+        def shutdown(hard=false)
+            action(hard ? 'shutdown-hard' : 'shutdown')
+        end
+
+        # Shuts down an already deployed VM, saving its state in the system DS
+        def undeploy(hard=false)
+            action(hard ? 'undeploy-hard' : 'undeploy')
+        end
+
+        # Powers off a running VM
+        def poweroff(hard=false)
+            action(hard ? 'poweroff-hard' : 'poweroff')
+        end
+
+        # Reboots an already deployed VM
+        def reboot(hard=false)
+            action(hard ? 'reboot-hard' : 'reboot')
+        end
+
+        # @deprecated use {#reboot}
+        def reset
+            reboot(true)
+        end
+
+        # @deprecated use {#shutdown}
+        def cancel
+            shutdown(true)
+        end
+
+        # Sets a VM to hold state, scheduler will not deploy it
+        def hold
+            action('hold')
+        end
+
+        # Releases a VM from hold state
+        def release
+            action('release')
+        end
+
+        # Stops a running VM
+        def stop
+            action('stop')
+        end
+
+        # Saves a running VM
+        def suspend
+            action('suspend')
+        end
+
+        # Resumes the execution of a saved VM
+        def resume
+            action('resume')
+        end
+
+        # Attaches a disk to a running VM
+        #
+        # @param disk_template [String] Template containing a DISK element
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def disk_attach(disk_template)
+            return call(VM_METHODS[:attach], @pe_id, disk_template)
+        end
+
+        alias_method :attachdisk, :disk_attach
+
+        # Detaches a disk from a running VM
+        #
+        # @param disk_id [Integer] Id of the disk to be detached
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def disk_detach(disk_id)
+            return call(VM_METHODS[:detach], @pe_id, disk_id)
+        end
+
+        alias_method :detachdisk, :disk_detach
+
+        # Attaches a NIC to a running VM
+        #
+        # @param nic_template [String] Template containing a NIC element
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def nic_attach(nic_template)
+            return call(VM_METHODS[:attachnic], @pe_id, nic_template)
+        end
+
+        # Detaches a NIC from a running VM
+        #
+        # @param nic_id [Integer] Id of the NIC to be detached
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def nic_detach(nic_id)
+            return call(VM_METHODS[:detachnic], @pe_id, nic_id)
+        end
+
+        # Deletes a VM from the pool
+        def delete(recreate=false)
+            if recreate
+                action('delete-recreate')
+            else
+                action('delete')
+            end
+        end
+
+        # @deprecated use {#delete} instead
+        def finalize(recreate=false)
+            delete(recreate)
+        end
+
+        # Forces a re-deployment of a VM in UNKNOWN or BOOT state
+        def boot
+            action('boot')
+        end
+
+        alias_method :restart, :boot
+
+        # @deprecated use {#delete} instead
+        def resubmit
+            action('delete-recreate')
+        end
+
+        # Sets the re-scheduling flag for the VM
+        def resched
+            action('resched')
+        end
+
+        # Unsets the re-scheduling flag for the VM
+        def unresched
+            action('unresched')
+        end
+
+        # Moves a running VM to the specified host. With live=true the
+        # migration is done withdout downtime.
+        #
+        # @param host_id [Interger] The host id (hid) of the target host where
+        #   the VM will be migrated.
+        # @param live [true|false] If true the migration is done without
+        #   downtime. Defaults to false
+        # @param enforce [true|false] If it is set to true, the host capacity
+        #   will be checked, and the deployment will fail if the host is
+        #   overcommited. Defaults to false
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def migrate(host_id, live=false, enforce=false)
+            call(VM_METHODS[:migrate], @pe_id, host_id.to_i, live==true,
+                enforce)
+        end
+
+        # @deprecated use {#migrate} instead
+        def live_migrate(host_id, enforce=false)
+            migrate(host_id, true, enforce)
+        end
+
+        # Set the specified vm's disk to be saved in a new image
+        # when the VirtualMachine shutdowns
+        #
+        # @param disk_id [Integer] ID of the disk to be saved
+        # @param image_name [String] Name for the new image where the
+        #   disk will be saved
+        # @param image_type [String] Type of the new image. Set to empty string
+        #   to use the default type
+        # @param hot [true|false] True to save the disk immediately, false will
+        #   perform the operation when the VM shuts down
+        #
+        # @return [Integer, OpenNebula::Error] the new Image ID in case of
+        #   success, error otherwise
+        def disk_snapshot(disk_id, image_name, image_type="", hot=false)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(VM_METHODS[:savedisk],
+                              @pe_id,
+                              disk_id,
+                              image_name,
+                              image_type,
+                              hot)
+
+            return rc
+        end
+
+        # @deprecated use {#disk_snapshot}
+        def save_as(disk_id, image_name, image_type="", hot=false)
+            return disk_snapshot(disk_id, image_name, image_type, hot)
+        end
+
+        # Resize the VM
+        #
+        # @param capacity_template [String] Template containing the new capacity
+        #   elements CPU, VCPU, MEMORY. If one of them is not present, or its
+        #   value is 0, it will not be resized
+        # @param enforce [true|false] If it is set to true, the host capacity
+        #   will be checked. This will only affect oneadmin requests, regular users
+        #   resize requests will always be enforced
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def resize(capacity_template, enforce)
+            return call(VM_METHODS[:resize], @pe_id, capacity_template, enforce)
+        end
+
+        # Changes the owner/group
+        # uid:: _Integer_ the new owner id. Set to -1 to leave the current one
+        # gid:: _Integer_ the new group id. Set to -1 to leave the current one
+        # [return] nil in case of success or an Error object
+        def chown(uid, gid)
+            super(VM_METHODS[:chown], uid, gid)
+        end
+
+        # Changes the permissions.
+        #
+        # @param octet [String] Permissions octed , e.g. 640
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod_octet(octet)
+            super(VM_METHODS[:chmod], octet)
+        end
+
+        # Changes the permissions.
+        # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
+                other_m, other_a)
+            super(VM_METHODS[:chmod], owner_u, owner_m, owner_a, group_u,
+                group_m, group_a, other_u, other_m, other_a)
+        end
+
+        # Retrieves this VM's monitoring data from OpenNebula
+        #
+        # @param [Array<String>] xpath_expressions Elements to retrieve.
+        #
+        # @return [Hash<String, Array<Array<int>>>, OpenNebula::Error] Hash with
+        #   the requested xpath expressions, and an Array of 'timestamp, value'.
+        #
+        # @example
+        #   vm.monitoring( ['CPU', 'NET_TX', 'TEMPLATE/CUSTOM_PROBE'] )
+        #
+        #   { "NET_TX" =>
+        #       [["1337264510", "210"],
+        #        ["1337264553", "220"],
+        #        ["1337264584", "230"]],
+        #     "TEMPLATE/CUSTOM_PROBE" =>
+        #       [],
+        #     "CPU" =>
+        #       [["1337264510", "0"],
+        #        ["1337264553", "0"],
+        #        ["1337264584", "0"]]
+        #   }
+        def monitoring(xpath_expressions)
+            return super(VM_METHODS[:monitoring], 'VM',
+                'LAST_POLL', xpath_expressions)
+        end
+
+        # Retrieves this VM's monitoring data from OpenNebula, in XML
+        #
+        # @return [String] VM monitoring data, in XML
+        def monitoring_xml()
+            return Error.new('ID not defined') if !@pe_id
+
+            return @client.call(VM_METHODS[:monitoring], @pe_id)
+        end
+
+        # Renames this VM
+        #
+        # @param name [String] New name for the VM.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def rename(name)
+            return call(VM_METHODS[:rename], @pe_id, name)
+        end
+
+        # Creates a new VM snapshot
+        #
+        # @param name [String] Name for the snapshot.
+        #
+        # @return [Integer, OpenNebula::Error] The new snaphost ID in case
+        #   of success, Error otherwise
+        def snapshot_create(name="")
+            return Error.new('ID not defined') if !@pe_id
+
+            name ||= ""
+            return @client.call(VM_METHODS[:snapshotcreate], @pe_id, name)
+        end
+
+        # Reverts to a snapshot
+        #
+        # @param snap_id [Integer] Id of the snapshot
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def snapshot_revert(snap_id)
+            return call(VM_METHODS[:snapshotrevert], @pe_id, snap_id)
+        end
+
+        # Deletes a  VM snapshot
+        #
+        # @param snap_id [Integer] Id of the snapshot
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def snapshot_delete(snap_id)
+            return call(VM_METHODS[:snapshotdelete], @pe_id, snap_id)
+        end
+
+        # Recovers an ACTIVE VM
+        #
+        # @param result [Boolean] Recover with success (true) or failure (false)
+        # @param result [info] Additional information needed to recover the VM
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def recover(result)
+            return call(VM_METHODS[:recover], @pe_id, result)
+        end
+
+        ########################################################################
+        # Helpers to get VirtualMachine information
+        ########################################################################
+
+        # Returns the VM state of the VirtualMachine (numeric value)
+        def state
+            self['STATE'].to_i
+        end
+
+        # Returns the VM state of the VirtualMachine (string value)
+        def state_str
+            VM_STATE[state]
+        end
+
+        # Returns the LCM state of the VirtualMachine (numeric value)
+        def lcm_state
+            self['LCM_STATE'].to_i
+        end
+
+        # Returns the LCM state of the VirtualMachine (string value)
+        def lcm_state_str
+            LCM_STATE[lcm_state]
+        end
+
+        # Returns the short status string for the VirtualMachine
+        def status
+            short_state_str=SHORT_VM_STATES[state_str]
+
+            if short_state_str=="actv"
+                short_state_str=SHORT_LCM_STATES[lcm_state_str]
+            end
+
+            short_state_str
+        end
+
+        # Returns the group identifier
+        # [return] _Integer_ the element's group ID
+        def gid
+            self['GID'].to_i
+        end
+
+    private
+        def action(name)
+            return Error.new('ID not defined') if !@pe_id
+
+            rc = @client.call(VM_METHODS[:action], name, @pe_id)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/virtual_machine_pool.rb b/ruby-opennebula-4.4/lib/opennebula/virtual_machine_pool.rb
new file mode 100644 (file)
index 0000000..2932bf3
--- /dev/null
@@ -0,0 +1,323 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class VirtualMachinePool < Pool
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+
+        VM_POOL_METHODS = {
+            :info       => "vmpool.info",
+            :monitoring => "vmpool.monitoring",
+            :accounting => "vmpool.accounting"
+        }
+
+        # Constants for info queries (include/RequestManagerPoolInfoFilter.h)
+        INFO_NOT_DONE = -1
+        INFO_ALL_VM   = -2
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+
+        # +client+ a Client object that represents a XML-RPC connection
+        # +user_id+ is to refer to a Pool with VirtualMachines from that user
+        def initialize(client, user_id=0)
+            super('VM_POOL','VM',client)
+
+            @user_id  = user_id
+        end
+
+        # Default Factory Method for the Pools
+        def factory(element_xml)
+            OpenNebula::VirtualMachine.new(element_xml,@client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Virtual Network Object
+        #######################################################################
+
+        # Retrieves all or part of the VirtualMachines in the pool.
+        # No arguments, returns the not-in-done VMs for the user
+        # [user_id, start_id, end_id]
+        # [user_id, start_id, end_id, state]
+        def info(*args)
+            case args.size
+                when 0
+                    info_filter(VM_POOL_METHODS[:info],
+                                @user_id,
+                                -1,
+                                -1,
+                                INFO_NOT_DONE)
+                when 1
+                    info_filter(VM_POOL_METHODS[:info],
+                                args[0],
+                                -1,
+                                -1,
+                                INFO_NOT_DONE)
+                when 3
+                    info_filter(VM_POOL_METHODS[:info],
+                                args[0],
+                                args[1],
+                                args[2],
+                                INFO_NOT_DONE)
+                when 4
+                    info_filter(VM_POOL_METHODS[:info],
+                                args[0],
+                                args[1],
+                                args[2],
+                                args[3])
+            end
+        end
+
+        def info_all()
+            return info_filter(VM_POOL_METHODS[:info],
+                               INFO_ALL,
+                               -1,
+                               -1,
+                               INFO_NOT_DONE)
+        end
+
+        def info_mine()
+            return info_filter(VM_POOL_METHODS[:info],
+                               INFO_MINE,
+                               -1,
+                               -1,
+                               INFO_NOT_DONE)
+        end
+
+        def info_group()
+            return info_filter(VM_POOL_METHODS[:info],
+                               INFO_GROUP,
+                               -1,
+                               -1,
+                               INFO_NOT_DONE)
+        end
+
+        alias_method :info!, :info
+        alias_method :info_all!, :info_all
+        alias_method :info_mine!, :info_mine
+        alias_method :info_group!, :info_group
+
+        # Retrieves the monitoring data for all the VMs in the pool
+        #
+        # @param [Array<String>] xpath_expressions Elements to retrieve.
+        # @param [Integer] filter_flag Optional filter flag to retrieve all or
+        #   part of the Pool. Possible values: INFO_ALL, INFO_GROUP, INFO_MINE.
+        #
+        # @return [Hash<String, <Hash<String, Array<Array<int>>>>>,
+        #   OpenNebula::Error] The first level hash uses the VM ID as keys, and
+        #   as value a Hash with the requested xpath expressions,
+        #   and an Array of 'timestamp, value'.
+        #
+        # @example
+        #   vm_pool.monitoring( ['CPU', 'NET_TX', 'TEMPLATE/CUSTOM_PROBE'] )
+        #
+        #   {"1"=>
+        #    {"CPU"=>
+        #      [["1337608271", "0"], ["1337608301", "0"], ["1337608331", "0"]],
+        #     "NET_TX"=>
+        #      [["1337608271", "510"], ["1337608301", "510"], ["1337608331", "520"]],
+        #     "TEMPLATE/CUSTOM_PROBE"=>
+        #      []},
+        #
+        #   "0"=>
+        #    {"CPU"=>
+        #      [["1337608271", "0"], ["1337608301", "0"], ["1337608331", "0"]],
+        #     "NET_TX"=>
+        #      [["1337608271", "510"], ["1337608301", "510"], ["1337608331", "520"]],
+        #     "TEMPLATE/CUSTOM_PROBE"=>
+        #      []}}
+        def monitoring(xpath_expressions, filter_flag=INFO_ALL)
+            return super(VM_POOL_METHODS[:monitoring],
+                'VM', 'LAST_POLL', xpath_expressions, filter_flag)
+        end
+
+        # Retrieves the monitoring data for all the VMs in the pool, in XML
+        #
+        # @param [Integer] filter_flag Optional filter flag to retrieve all or
+        #   part of the Pool. Possible values: INFO_ALL, INFO_GROUP, INFO_MINE.
+        #
+        # @return [String] VM monitoring data, in XML
+        def monitoring_xml(filter_flag=INFO_ALL)
+            return @client.call(VM_POOL_METHODS[:monitoring], filter_flag)
+        end
+
+        # Retrieves the accounting data for all the VMs in the pool
+        #
+        # @param [Integer] filter_flag Optional filter flag to retrieve all or
+        #   part of the Pool. Possible values: INFO_ALL, INFO_GROUP, INFO_MINE
+        #   or user_id
+        # @param [Hash] options
+        # @option params [Integer] :start_time Start date and time to take into account,
+        #   if no start_time is required use -1
+        # @option params [Integer] :end_time End date and time to take into account,
+        #   if no end_time is required use -1
+        # @option params [Integer] :host Host id to filter the results
+        # @option params [Integer] :group Group id to filter the results
+        # @option params [String] :xpath Xpath expression to filter the results.
+        #    For example: HISTORY[ETIME>0]
+        # @option params [String] :order_by_1 Xpath expression to group the
+        # @option params [String] :order_by_2 Xpath expression to group the
+        #   returned hash. This will be the second level of the hash
+        #
+        # @return [Hash, OpenNebula::Error]
+        #   The first level hash uses the :order_by_1 values as keys, and
+        #   as value a Hash with the :order_by_2 values and the HISTORY_RECORDS
+        #
+        # @example
+        #   {"HISTORY_RECORDS"=>
+        #       {"HISTORY"=> [
+        #         {"OID"=>"0",
+        #          "SEQ"=>"0",
+        #          "HOSTNAME"=>"dummy",
+        #          ...
+        #         },
+        #         {"OID"=>"0",
+        #          "SEQ"=>"0",
+        #          "HOSTNAME"=>"dummy",
+        #
+        # @example :order_by_1 => VM/UID
+        #   {"0"=>
+        #       {"HISTORY_RECORDS"=>
+        #          {"HISTORY"=> [
+        #            {"OID"=>"0",
+        #             "SEQ"=>"0",
+        #             "HOSTNAME"=>"dummy",
+        #             ...
+        #            },
+        #            {"OID"=>"0",
+        #             "SEQ"=>"0",
+        #             "HOSTNAME"=>"dummy",
+        #
+        # @example :order_by_1 => VM/UID, :order_by_2 => VM/ID
+        #   {"0"=>
+        #       {"0"=>
+        #           {"HISTORY_RECORDS"=>
+        #               {"HISTORY"=> [
+        #                 {"OID"=>"0",
+        #                  "SEQ"=>"0",
+        #                  "HOSTNAME"=>"dummy",
+        #                  ...
+        #                 },
+        #                 {"OID"=>"0",
+        #                  "SEQ"=>"0",
+        #                  "HOSTNAME"=>"dummy",
+        #
+        def accounting(filter_flag=INFO_ALL, options={})
+            acct_hash = Hash.new
+
+            rc = build_accounting(filter_flag, options) do |history|
+                hash = acct_hash
+
+                if options[:order_by_1]
+                    id_1 = history[options[:order_by_1]]
+                    acct_hash[id_1] ||= Hash.new
+
+                    if options[:order_by_2]
+                        id_2 = history[options[:order_by_2]]
+                        acct_hash[id_1][id_2] ||= Hash.new
+
+                        hash = acct_hash[id_1][id_2]
+                    else
+                        hash = acct_hash[id_1]
+                    end
+                end
+
+                hash["HISTORY_RECORDS"] ||= Hash.new
+                hash["HISTORY_RECORDS"]["HISTORY"] ||= Array.new
+                hash["HISTORY_RECORDS"]["HISTORY"] << history.to_hash['HISTORY']
+            end
+
+            return rc if OpenNebula.is_error?(rc)
+
+            acct_hash
+        end
+
+        # Retrieves the accounting data for all the VMs in the pool in xml
+        #
+        # @param [Integer] filter_flag Optional filter flag to retrieve all or
+        #   part of the Pool. Possible values: INFO_ALL, INFO_GROUP, INFO_MINE
+        #   or user_id
+        # @param [Hash] options
+        # @option params [Integer] :start_time Start date and time to take into account,
+        #   if no start_time is required use -1
+        # @option params [Integer] :end_time End date and time to take into account,
+        #   if no end_time is required use -1
+        # @option params [Integer] :host Host id to filter the results
+        # @option params [Integer] :group Group id to filter the results
+        # @option params [String] :xpath Xpath expression to filter the results.
+        #    For example: HISTORY[ETIME>0]
+        #
+        # @return [String] the xml representing the accounting data
+        def accounting_xml(filter_flag=INFO_ALL, options={})
+            acct_hash = Hash.new
+            xml_str = "<HISTORY_RECORDS>\n"
+
+            rc = build_accounting(filter_flag, options) do |history|
+                xml_str << history.to_xml
+            end
+
+            return rc if OpenNebula.is_error?(rc)
+
+            xml_str << "\n</HISTORY_RECORDS>"
+            xml_str
+        end
+
+        private
+
+        def build_accounting(filter_flag, options, &block)
+            xml_str = @client.call(VM_POOL_METHODS[:accounting],
+                        filter_flag,
+                        options[:start_time],
+                        options[:end_time])
+
+            return xml_str if OpenNebula.is_error?(xml_str)
+
+            xmldoc = XMLElement.new
+            xmldoc.initialize_xml(xml_str, 'HISTORY_RECORDS')
+
+            xpath_array = Array.new
+            xpath_array << "HISTORY[HID=#{options[:host]}]" if options[:host]
+            xpath_array << "HISTORY[VM/GID=#{options[:group]}]" if options[:group]
+            xpath_array << options[:xpath] if options[:xpath]
+
+            if xpath_array.empty?
+                xpath_str = "HISTORY"
+            else
+                xpath_str = xpath_array.join(' | ')
+            end
+
+            acct_hash = Hash.new
+
+            xmldoc.each(xpath_str) do |history|
+                block.call(history)
+            end
+
+            acct_hash
+        end
+
+        def info_filter(xml_method, who, start_id, end_id, state)
+            return xmlrpc_info(xml_method, who, start_id, end_id, state)
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/virtual_network.rb b/ruby-opennebula-4.4/lib/opennebula/virtual_network.rb
new file mode 100644 (file)
index 0000000..1ac2b66
--- /dev/null
@@ -0,0 +1,253 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool_element'
+
+module OpenNebula
+    class VirtualNetwork < PoolElement
+        #######################################################################
+        # Constants and Class Methods
+        #######################################################################
+
+
+        VN_METHODS = {
+            :info       => "vn.info",
+            :allocate   => "vn.allocate",
+            :delete     => "vn.delete",
+            :addleases  => "vn.addleases",
+            :rmleases   => "vn.rmleases",
+            :chown      => "vn.chown",
+            :chmod      => "vn.chmod",
+            :update     => "vn.update",
+            :hold       => "vn.hold",
+            :release    => "vn.release",
+            :rename     => "vn.rename"
+        }
+
+        VN_TYPES=%w{RANGED FIXED}
+
+        SHORT_VN_TYPES={
+            "RANGED" => "R",
+            "FIXED"  => "F"
+        }
+
+        # Creates a VirtualNetwork description with just its identifier
+        # this method should be used to create plain VirtualNetwork objects.
+        # +id+ the id of the network
+        #
+        # Example:
+        #   vnet = VirtualNetwork.new(VirtualNetwork.build_xml(3),rpc_client)
+        #
+        def VirtualNetwork.build_xml(pe_id=nil)
+            if pe_id
+                vn_xml = "<VNET><ID>#{pe_id}</ID></VNET>"
+            else
+                vn_xml = "<VNET></VNET>"
+            end
+
+            XMLElement.build_xml(vn_xml, 'VNET')
+        end
+
+        # Class constructor
+        def initialize(xml, client)
+            super(xml,client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Virtual Network Object
+        #######################################################################
+
+        # Retrieves the information of the given VirtualNetwork.
+        def info()
+            super(VN_METHODS[:info], 'VNET')
+        end
+
+        alias_method :info!, :info
+
+        # Allocates a new VirtualNetwork in OpenNebula
+        #
+        # @param description [String] The template of the VirtualNetwork.
+        # @param cluster_id [Integer] Id of the cluster
+        #
+        # @return [Integer, OpenNebula::Error] the new ID in case of
+        #   success, error otherwise
+        def allocate(description,cluster_id=ClusterPool::NONE_CLUSTER_ID)
+            super(VN_METHODS[:allocate], description, cluster_id)
+        end
+
+        # Replaces the template contents
+        #
+        # @param new_template [String] New template contents
+        # @param append [true, false] True to append new attributes instead of
+        #   replace the whole template
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def update(new_template=nil, append=false)
+            super(VN_METHODS[:update], new_template, append ? 1 : 0)
+        end
+
+        # Publishes the VirtualNetwork, to be used by other users
+        def publish
+            set_publish(true)
+        end
+
+        # Unplubishes the VirtualNetwork
+        def unpublish
+            set_publish(false)
+        end
+
+        # Deletes the VirtualNetwork
+        def delete()
+            super(VN_METHODS[:delete])
+        end
+
+        # Adds a lease to the VirtualNetwork
+        def addleases(ip, mac = nil)
+            return Error.new('ID not defined') if !@pe_id
+
+            lease_template = "LEASES = [ IP = #{ip}"
+            lease_template << ", MAC = #{mac}" if mac
+            lease_template << " ]"
+
+            rc = @client.call(VN_METHODS[:addleases], @pe_id, lease_template)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Removes a lease from the VirtualNetwork
+        def rmleases(ip)
+            return Error.new('ID not defined') if !@pe_id
+
+            lease_template = "LEASES = [ IP = #{ip} ]"
+
+            rc = @client.call(VN_METHODS[:rmleases], @pe_id, lease_template)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Holds a virtual network Lease as used
+        # @param ip [String] IP to hold
+        def hold(ip)
+            return Error.new('ID not defined') if !@pe_id
+
+            lease_template = "LEASES = [ IP = #{ip} ]"
+
+            rc = @client.call(VN_METHODS[:hold], @pe_id, lease_template)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Releases a virtual network Lease on hold
+        # @param ip [String] IP to release
+        def release(ip)
+            return Error.new('ID not defined') if !@pe_id
+
+            lease_template = "LEASES = [ IP = #{ip} ]"
+
+            rc = @client.call(VN_METHODS[:release], @pe_id, lease_template)
+            rc = nil if !OpenNebula.is_error?(rc)
+
+            return rc
+        end
+
+        # Changes the owner/group
+        #
+        # @param uid [Integer] the new owner id. Set to -1 to leave the current one
+        # @param gid [Integer] the new group id. Set to -1 to leave the current one
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chown(uid, gid)
+            super(VN_METHODS[:chown], uid, gid)
+        end
+
+        # Changes the virtual network permissions.
+        #
+        # @param octet [String] Permissions octed , e.g. 640
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod_octet(octet)
+            super(VN_METHODS[:chmod], octet)
+        end
+
+        # Changes the virtual network permissions.
+        # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
+                other_m, other_a)
+            super(VN_METHODS[:chmod], owner_u, owner_m, owner_a, group_u,
+                group_m, group_a, other_u, other_m, other_a)
+        end
+        
+        # Renames this virtual network
+        #
+        # @param name [String] New name for the virtual network.
+        #
+        # @return [nil, OpenNebula::Error] nil in case of success, Error
+        #   otherwise
+        def rename(name)
+            return call(VN_METHODS[:rename], @pe_id, name)
+        end
+
+        #######################################################################
+        # Helpers to get VirtualNetwork information
+        #######################################################################
+
+        # Returns the group identifier
+        # [return] _Integer_ the element's group ID
+        def gid
+            self['GID'].to_i
+        end
+
+        # Returns the type of the Virtual Network (numeric value)
+        def type
+            self['TYPE'].to_i
+        end
+
+        # Returns the type of the Virtual Network (string value)
+        def type_str
+            VN_TYPES[type]
+        end
+
+        # Returns the state of the Virtual Network (string value)
+        def short_type_str
+            SHORT_VN_TYPES[type_str]
+        end
+
+        def public?
+            if self['PERMISSIONS/GROUP_U'] == "1" || self['PERMISSIONS/OTHER_U'] == "1"
+                true
+            else
+                false
+            end
+        end
+
+    private
+        def set_publish(published)
+            group_u = published ? 1 : 0
+
+            chmod(-1, -1, -1, group_u, -1, -1, -1, -1, -1)
+        end
+
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/virtual_network_pool.rb b/ruby-opennebula-4.4/lib/opennebula/virtual_network_pool.rb
new file mode 100644 (file)
index 0000000..38a8acc
--- /dev/null
@@ -0,0 +1,79 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/pool'
+
+module OpenNebula
+    class VirtualNetworkPool < Pool
+        #######################################################################
+        # Constants and Class attribute accessors
+        #######################################################################
+
+
+        VN_POOL_METHODS = {
+            :info => "vnpool.info"
+        }
+
+        #######################################################################
+        # Class constructor & Pool Methods
+        #######################################################################
+
+        # +client+ a Client object that represents a XML-RPC connection
+        # +user_id+ is to refer to a Pool with VirtualNetworks from that user
+        def initialize(client, user_id=0)
+            super('VNET_POOL','VNET',client)
+
+            @user_id  = user_id
+        end
+
+        # Default Factory Method for the Pools
+        def factory(element_xml)
+            OpenNebula::VirtualNetwork.new(element_xml,@client)
+        end
+
+        #######################################################################
+        # XML-RPC Methods for the Virtual Network Object
+        #######################################################################
+
+        # Retrieves all or part of the VirtualMachines in the pool.
+        def info(*args)
+            case args.size
+                when 0
+                    info_filter(VN_POOL_METHODS[:info],@user_id,-1,-1)
+                when 3
+                    info_filter(VN_POOL_METHODS[:info],args[0],args[1],args[2])
+            end
+        end
+
+        def info_all()
+            return super(VN_POOL_METHODS[:info])
+        end
+
+        def info_mine()
+            return super(VN_POOL_METHODS[:info])
+        end
+
+        def info_group()
+            return super(VN_POOL_METHODS[:info])
+        end
+
+        alias_method :info!, :info
+        alias_method :info_all!, :info_all
+        alias_method :info_mine!, :info_mine
+        alias_method :info_group!, :info_group
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/x509_auth.rb b/ruby-opennebula-4.4/lib/opennebula/x509_auth.rb
new file mode 100644 (file)
index 0000000..24ff82d
--- /dev/null
@@ -0,0 +1,288 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'openssl'
+require 'base64'
+require 'fileutils'
+require 'yaml'
+
+module OpenNebula; end
+
+# X509 authentication class. It can be used as a driver for auth_mad
+# as auth method is defined. It also holds some helper methods to be used
+# by oneauth command
+class OpenNebula::X509Auth
+    ###########################################################################
+    #Constants with paths to relevant files and defaults
+    ###########################################################################
+    if !ENV["ONE_LOCATION"]
+        ETC_LOCATION      = "/etc/one"
+    else
+        ETC_LOCATION      = ENV["ONE_LOCATION"] + "/etc"
+    end
+
+    LOGIN_PATH = ENV['HOME']+'/.one/one_x509'
+
+    X509_AUTH_CONF_PATH = ETC_LOCATION + "/auth/x509_auth.conf"
+
+    X509_DEFAULTS = {
+        :ca_dir   => ETC_LOCATION + "/auth/certificates"
+    }
+
+    def self.escape_dn(dn)
+        dn.gsub(/\s/) { |s| "\\"+s[0].ord.to_s(16) }
+    end
+
+    def self.unescape_dn(dn)
+        dn.gsub(/\\[0-9a-f]{2}/) { |s| s[1,2].to_i(16).chr }
+    end
+
+    ###########################################################################
+    # Initialize x509Auth object
+    #
+    # @param [Hash] default options for path
+    # @option options [String] :certs_pem
+    #         cert chain array in colon-separated pem format
+    # @option options [String] :key_pem
+    #         key in pem format
+    # @option options [String] :ca_dir
+    #         directory of trusted CA's. Needed for auth method, not for login.
+    def initialize(options={})
+        @options ||= X509_DEFAULTS
+        @options.merge!(options)
+
+        load_options(X509_AUTH_CONF_PATH)
+
+        @cert_chain = @options[:certs_pem].collect do |cert_pem|
+            OpenSSL::X509::Certificate.new(cert_pem)
+        end
+
+        if @options[:key_pem]
+            @key  = OpenSSL::PKey::RSA.new(@options[:key_pem])
+        end
+    end
+
+    ###########################################################################
+    # Client side
+    ###########################################################################
+
+    # Creates the login file for x509 authentication at ~/.one/one_x509.
+    # By default it is valid as long as the certificate is valid. It can
+    # be changed to any number of seconds with expire parameter (sec.)
+    def login(user, expire=0)
+        write_login(login_token(user,expire))
+    end
+
+    # Returns a valid password string to create a user using this auth driver.
+    # In this case the dn of the user certificate.
+    def password
+        self.class.escape_dn(@cert_chain[0].subject.to_s)
+    end
+
+    # Generates a login token in the form:
+    # user_name:x509:user_name:time_expires:cert_chain
+    #   - user_name:time_expires is encrypted with the user certificate
+    #   - user_name:time_expires:cert_chain is base64 encoded
+    def login_token(user, expire)
+        if expire != 0
+            expires = Time.now.to_i + expire.to_i
+        else
+            expires = @cert_chain[0].not_after.to_i
+        end
+
+        text_to_sign = "#{user}:#{expires}"
+        signed_text  = encrypt(text_to_sign)
+
+        certs_pem = @cert_chain.collect{|cert| cert.to_pem}.join(":")
+
+        token     = "#{signed_text}:#{certs_pem}"
+        token64   = Base64::encode64(token).strip.delete("\n")
+
+        login_out = "#{user}:#{token64}"
+
+        login_out
+    end
+
+    ###########################################################################
+    # Server side
+    ###########################################################################
+    # auth method for auth_mad
+    def authenticate(user, pass, signed_text)
+        begin
+            # Decryption demonstrates that the user posessed the private key.
+            _user, expires = decrypt(signed_text).split(':')
+
+            return "User name missmatch" if user != _user
+
+            return "x509 proxy expired"  if Time.now.to_i >= expires.to_i
+
+            # Some DN in the chain must match a DN in the password
+            dn_ok = @cert_chain.each do |cert|
+                if pass.split('|').include?(
+                        self.class.escape_dn(cert.subject.to_s))
+                    break true
+                end
+            end
+
+            unless dn_ok == true
+                return "Certificate subject missmatch"
+            end
+
+            validate
+
+            return true
+        rescue => e
+            return e.message
+        end
+    end
+
+private
+    # Writes a login_txt to the login file as defined in LOGIN_PATH
+    # constant
+    def write_login(login_txt)
+        # Inits login file path and creates ~/.one directory if needed
+        # Set instance variables
+        login_dir = File.dirname(LOGIN_PATH)
+
+        begin
+            FileUtils.mkdir_p(login_dir)
+        rescue Errno::EEXIST
+        end
+
+        file = File.open(LOGIN_PATH, "w")
+        file.write(login_txt)
+        file.close
+
+        File.chmod(0600,LOGIN_PATH)
+    end
+
+    # Load class options form a configuration file (yaml syntax)
+    def load_options(conf_file)
+        if File.readable?(conf_file)
+            conf_txt = File.read(conf_file)
+            conf_opt = YAML::load(conf_txt)
+
+            @options.merge!(conf_opt) if conf_opt != false
+        end
+    end
+
+    ###########################################################################
+    #                       Methods to encrpyt/decrypt keys
+    ###########################################################################
+    # Encrypts data with the private key of the user and returns
+    # base 64 encoded output in a single line
+    def encrypt(data)
+        return nil if !@key
+        Base64::encode64(@key.private_encrypt(data)).delete("\n").strip
+    end
+
+    # Decrypts base 64 encoded data with pub_key (public key)
+    def decrypt(data)
+        @cert_chain[0].public_key.public_decrypt(Base64::decode64(data))
+    end
+
+    ###########################################################################
+    # Validate the user certificate
+    ###########################################################################
+    def validate
+        now    = Time.now
+
+        # Check start time and end time of certificates
+        @cert_chain.each do |cert|
+            if cert.not_before > now || cert.not_after < now
+                raise failed +  "Certificate not valid. Current time is " +
+                  now.localtime.to_s + "."
+            end
+        end
+
+        begin
+            # Validate the proxy certifcates
+            signee = @cert_chain[0]
+
+            check_crl(signee)
+
+            @cert_chain[1..-1].each do |cert|
+                if !((signee.issuer.to_s == cert.subject.to_s) &&
+                     (signee.verify(cert.public_key)))
+                    raise  failed + signee.subject.to_s + " with issuer " +
+                           signee.issuer.to_s + " was not verified by " +
+                           cert.subject.to_s + "."
+                end
+                signee = cert
+            end
+
+            # Validate the End Entity certificate
+            if !@options[:ca_dir]
+                raise failed + "No certifcate authority directory was specified."
+            end
+
+            begin
+                ca_hash = signee.issuer.hash.to_s(16)
+                ca_path = @options[:ca_dir] + '/' + ca_hash + '.0'
+
+                ca_cert = OpenSSL::X509::Certificate.new(File.read(ca_path))
+
+                if !((signee.issuer.to_s == ca_cert.subject.to_s) &&
+                     (signee.verify(ca_cert.public_key)))
+                    raise  failed + signee.subject.to_s + " with issuer " +
+                           signee.issuer.to_s + " was not verified by " +
+                           ca_cert.subject.to_s + "."
+                end
+
+                signee = ca_cert
+            end while ca_cert.subject.to_s != ca_cert.issuer.to_s
+        rescue
+            raise
+        end
+    end
+
+    def check_crl(signee)
+        failed = "Could not validate user credentials: "
+
+        ca_hash = signee.issuer.hash.to_s(16)
+        ca_path = @options[:ca_dir] + '/' + ca_hash + '.0'
+
+        crl_path = @options[:ca_dir] + '/' + ca_hash + '.r0'
+
+        if !File.exist?(crl_path)
+            if @options[:check_crl]
+                raise failed + "CRL file #{crl_path} does not exist"
+            else
+                return
+            end
+        end
+
+        ca_cert = OpenSSL::X509::Certificate.new( File.read(ca_path) )
+        crl_cert = OpenSSL::X509::CRL.new( File.read(crl_path) )
+
+        # First verify the CRL itself with its signer
+        unless crl_cert.verify( ca_cert.public_key ) then
+            raise failed + "CRL is not verified by its Signer"
+        end
+
+        # Extract the list of revoked certificates from the CRL
+        rc_array = crl_cert.revoked
+
+        # Loop over the list and compare with the target personal
+        # certificate
+        rc_array.each do |e|
+            if e.serial.eql?(signee.serial) then
+                raise failed + "#{signee.subject.to_s} is found in the "<<
+                    "CRL, i.e. it is revoked"
+            end
+        end
+    end
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/xml_element.rb b/ruby-opennebula-4.4/lib/opennebula/xml_element.rb
new file mode 100644 (file)
index 0000000..a39f566
--- /dev/null
@@ -0,0 +1,427 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 OpenNebula
+    # The XMLElement class provides an abstraction of the underlying
+    # XML parser engine. It provides XML-related methods for the Pool and
+    # PoolElement classes
+    class XMLElement
+
+        # xml:: _opaque xml object_ an xml object as returned by build_xml
+        def initialize(xml=nil)
+            @xml = xml
+        end
+
+        # Initialize a XML document for the element
+        # xml:: _String_ the XML document of the object
+        # root_element:: _String_ Base xml element
+        def initialize_xml(xml, root_element)
+            @xml = XMLElement.build_xml(xml, root_element)
+
+            if OpenNebula.is_error?(@xml)
+                @xml = nil
+            else
+                if NOKOGIRI
+                    if @xml.size == 0
+                        @xml = nil
+                    end
+                else
+                    if @xml.name != root_element
+                        @xml = nil
+                    end
+                end
+            end
+        end
+
+        # Builds a XML document
+        # xml:: _String_ the XML document of the object
+        # root_element:: _String_ Base xml element
+        # [return] _XML_ object for the underlying XML engine
+        def self.build_xml(xml, root_element)
+            begin
+                if NOKOGIRI
+                    doc = Nokogiri::XML(xml).xpath("/#{root_element}")
+                else
+                    doc = REXML::Document.new(xml).root
+                end
+            rescue Exception => e
+                return OpenNebula::Error.new(e.message)
+            end
+
+            return doc
+        end
+
+        # Extract a text element from the XML description of the PoolElement.
+        #
+        # @param [String] key Xpath expression
+        #
+        # @return [String, nil] If a text element is found, the element's
+        #   text value. Otherwise, an empty string or nil, depending
+        #   on the backend
+        #
+        # @example
+        #   vm['VID'] # gets VM id
+        #   vm['HISTORY/HOSTNAME'] # get the hostname from the history
+        def [](key)
+            if NOKOGIRI
+                element=@xml.xpath(key.to_s)
+
+                return nil if element.size == 0
+            else
+                element=@xml.elements[key.to_s]
+
+                return "" if element && !element.has_text?
+            end
+
+            element.text if element
+        end
+
+        # Delete an element from the xml
+        # xpath::_String_ xpath expression that selects the elemnts to be deleted
+        def delete_element(xpath)
+            if NOKOGIRI
+                @xml.xpath(xpath.to_s).remove
+            else
+                @xml.delete_element(xpath.to_s)
+            end
+        end
+
+        # Add a new element to the xml
+        # xpath::_String_ xpath xpression where the elemente will be added
+        # elems::_Hash_ Hash containing the pairs key-value to be included
+        # Examples:
+        #   add_element('VM', 'NEW_ITEM' => 'NEW_VALUE')
+        #     <VM><NEW_ITEM>NEW_VALUE</NEW_ITEM>...</VM>
+        #
+        #   add_element('VM/TEMPLATE', 'V1' => {'X1' => 'A1', 'Y2' => 'A2'})
+        #     <VM><TEMPLATE><V1><X1>A1</X1><Y2>A2</Y2>...</TEMPLATE></VM>
+        def add_element(xpath, elems)
+            elems.each { |key, value|
+                if value.instance_of?(Hash)
+                    if NOKOGIRI
+                        elem = Nokogiri::XML::Node.new key, @xml.document
+                        value.each { |k2, v2|
+                            child = Nokogiri::XML::Node.new k2, elem
+                            child.content = v2
+                            elem.add_child(child)
+                        }
+                        @xml.xpath(xpath.to_s).first.add_child(elem)
+                    else
+                        elem = REXML::Element.new(key)
+                        value.each { |k2, v2|
+                            elem.add_element(k2).text = v2
+                        }
+                        @xml.elements[xpath].add_element(elem)
+                    end
+                else
+                    if NOKOGIRI
+                        elem = Nokogiri::XML::Node.new key, @xml.document
+                        elem.content = value
+                        @xml.xpath(xpath.to_s).first.add_child(elem)
+                    else
+                        @xml.elements[xpath].add_element(key).text = value
+                    end
+                end
+            }
+        end
+
+        # Gets an array of text from elemenets extracted
+        # using  the XPATH  expression passed as filter
+        def retrieve_elements(filter)
+            elements_array = Array.new
+
+            if NOKOGIRI
+                @xml.xpath(filter.to_s).each { |pelem|
+                    elements_array << pelem.text if pelem.text
+                 }
+            else
+                @xml.elements.each(filter.to_s) { |pelem|
+                    elements_array << pelem.text if pelem.text
+                }
+            end
+
+            if elements_array.size == 0
+                return nil
+            else
+                return elements_array
+            end
+
+        end
+
+        # Gets an attribute from an elemenT
+        # key:: _String_ xpath for the element
+        # name:: _String_ name of the attribute
+        def attr(key,name)
+            value = nil
+
+            if NOKOGIRI
+                element=@xml.xpath(key.to_s.upcase)
+                if element.size == 0
+                    return nil
+                end
+
+                attribute = element.attr(name)
+
+                value = attribute.text if attribute != nil
+            else
+                element=@xml.elements[key.to_s.upcase]
+
+                value = element.attributes[name] if element != nil
+            end
+
+            return value
+        end
+
+        # Iterates over every Element in the XPath and calls the block with a
+        # a XMLElement
+        # block:: _Block_
+        def each(xpath_str,&block)
+            if NOKOGIRI
+                @xml.xpath(xpath_str).each { |pelem|
+                    block.call XMLElement.new(pelem)
+                }
+            else
+                @xml.elements.each(xpath_str) { |pelem|
+                    block.call XMLElement.new(pelem)
+                }
+            end
+        end
+
+        def each_xpath(xpath_str,&block)
+            if NOKOGIRI
+                @xml.xpath(xpath_str).each { |pelem|
+                    block.call pelem.text
+                }
+            else
+                @xml.elements.each(xpath_str) { |pelem|
+                    block.call pelem.text
+                }
+            end
+        end
+
+        def name
+            @xml.name
+        end
+
+        def text
+            if NOKOGIRI
+                @xml.content
+            else
+                @xml.text
+            end
+        end
+
+        # Returns wheter there are elements for a given XPath
+        # xpath_str:: _String_ XPath expression to locate the element
+        def has_elements?(xpath_str)
+            if NOKOGIRI
+                element = @xml.xpath(xpath_str.to_s.upcase)
+                return element != nil && element.children.size > 0
+            else
+                element = @xml.elements[xpath_str.to_s]
+                return element != nil && element.has_elements?
+            end
+        end
+
+        # Returns the <TEMPLATE> element in text form
+        # indent:: _Boolean_ indents the resulting string, default true
+        def template_str(indent=true)
+            template_like_str('TEMPLATE', indent)
+        end
+
+        # Returns the <TEMPLATE> element in XML form
+        def template_xml
+            if NOKOGIRI
+                @xml.xpath('TEMPLATE').to_s
+            else
+                @xml.elements['TEMPLATE'].to_s
+            end
+        end
+
+        # Returns the xml of an element
+        def element_xml(xpath)
+            if NOKOGIRI
+                @xml.xpath(xpath).to_s
+            else
+                @xml.elements[xpath].to_s
+            end
+        end
+
+        # Returns elements in text form
+        # root_element:: _String_ base element
+        # indent:: _Boolean_ indents the resulting string, default true
+        # xpath_exp:: _String_ filter elements with a XPath
+        def template_like_str(root_element, indent=true, xpath_exp=nil)
+            if NOKOGIRI
+                xml_template = @xml.xpath(root_element).to_s
+                rexml        = REXML::Document.new(xml_template).root
+            else
+                rexml = @xml.elements[root_element]
+            end
+
+            if indent
+                ind_enter = "\n"
+                ind_tab   = '  '
+            else
+                ind_enter = ''
+                ind_tab   = ' '
+            end
+
+            str = rexml.elements.collect(xpath_exp) {|n|
+                next if n.class != REXML::Element
+
+                str_line = ""
+
+                if n.has_elements?
+                    str_line << "#{n.name}=[#{ind_enter}" << n.collect { |n2|
+
+                        next if n2.class != REXML::Element or !n2.has_text?
+
+                        str = "#{ind_tab}#{n2.name}=#{attr_to_str(n2.text)}"
+
+                    }.compact.join(",#{ind_enter}") << " ]"
+                else
+                    next if !n.has_text?
+
+                    str_line << "#{n.name}=#{attr_to_str(n.text)}"
+                end
+
+                str_line
+            }.compact.join("\n")
+
+            return str
+        end
+
+        #
+        #
+        #
+        def to_xml(pretty=false)
+            if NOKOGIRI && pretty
+                str = @xml.to_xml
+            elsif REXML_FORMATTERS && pretty
+                str = String.new
+
+                formatter = REXML::Formatters::Pretty.new
+                formatter.compact = true
+
+                formatter.write(@xml,str)
+            else
+                str = @xml.to_s
+            end
+
+            return str
+        end
+
+        # @return [Hash] a hash representing the resource
+        def to_hash
+            hash = {}
+
+            if NOKOGIRI
+                if @xml.instance_of?(Nokogiri::XML::NodeSet)
+                    @xml.each { |c|
+                        if c.element?
+                            build_hash(hash, c)
+                        end
+                    }
+                else
+                    build_hash(hash, @xml)
+                end
+            else
+                build_hash(hash, @xml)
+            end
+
+            hash
+        end
+
+        private
+
+        #
+        #
+        #
+        def build_hash(hash, element)
+            if NOKOGIRI
+                array = element.children
+                if array.length==1 and (array.first.text? or array.first.cdata?)
+                    r = array.first.text
+                else
+                    r = {}
+                    array.each { |c|
+                        if c.element?
+                            build_hash(r, c)
+                        end
+                    }
+                end
+            else
+                r = {}
+                if element.has_elements?
+                    element.each_element { |c| build_hash(r, c) }
+                elsif element.has_text?
+                    r = element.text
+                end
+            end
+
+            key = element.name
+            if hash.has_key?(key)
+                if hash[key].instance_of?(Array)
+                    hash[key] << r
+                else
+                    hash[key] = [hash[key], r]
+                end
+            else
+                hash[key] = r
+            end
+
+            hash
+        end
+
+        #
+        #
+        #
+        def attr_to_str(attr)
+            attr.gsub!('"',"\\\"")
+            attr = "\"#{attr}\""
+
+            return attr
+        end
+    end
+
+    # The XMLUtilsPool module provides an abstraction of the underlying
+    # XML parser engine. It provides XML-related methods for the Pools
+    class XMLPool < XMLElement
+
+        def initialize(xml=nil)
+            super(xml)
+        end
+
+        #Executes the given block for each element of the Pool
+        #block:: _Block_
+        def each_element(block)
+            if NOKOGIRI
+                @xml.xpath(
+                    "#{@element_name}").each {|pelem|
+                    block.call self.factory(pelem)
+                }
+            else
+                @xml.elements.each(
+                    "#{@element_name}") {|pelem|
+                    block.call self.factory(pelem)
+                }
+            end
+        end
+    end
+
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/xml_pool.rb b/ruby-opennebula-4.4/lib/opennebula/xml_pool.rb
new file mode 100644 (file)
index 0000000..0d5f65b
--- /dev/null
@@ -0,0 +1,45 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/xml_element'
+
+module OpenNebula
+    # The XMLUtilsPool module provides an abstraction of the underlying
+    # XML parser engine. It provides XML-related methods for the Pools
+    class XMLPool < XMLElement
+
+        def initialize(xml=nil)
+            super(xml)
+        end
+
+        #Executes the given block for each element of the Pool
+        #block:: _Block_
+        def each_element(block)
+            if NOKOGIRI
+                @xml.xpath(
+                    "#{@element_name}").each {|pelem|
+                    block.call self.factory(pelem)
+                }
+            else
+                @xml.elements.each(
+                    "#{@element_name}") {|pelem|
+                    block.call self.factory(pelem)
+                }
+            end
+        end
+    end
+
+end
diff --git a/ruby-opennebula-4.4/lib/opennebula/xml_utils.rb b/ruby-opennebula-4.4/lib/opennebula/xml_utils.rb
new file mode 100644 (file)
index 0000000..e4088ca
--- /dev/null
@@ -0,0 +1,34 @@
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        #
+#                                                                            #
+# 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 'opennebula/xml_pool'
+
+module OpenNebula
+
+    begin
+        require 'nokogiri'
+        NOKOGIRI=true
+    rescue LoadError
+        NOKOGIRI=false
+    end
+
+    begin
+        require 'rexml/formatters/pretty'
+        REXML_FORMATTERS=true
+    rescue LoadError
+        REXML_FORMATTERS=false
+    end
+end
diff --git a/ruby-opennebula-4.4/metadata.yml b/ruby-opennebula-4.4/metadata.yml
new file mode 100644 (file)
index 0000000..fc61427
--- /dev/null
@@ -0,0 +1,112 @@
+--- !ruby/object:Gem::Specification
+name: opennebula
+version: !ruby/object:Gem::Version
+  version: 4.4.0
+platform: ruby
+authors:
+- OpenNebula
+autorequire: 
+bindir: bin
+cert_chain: []
+date: 2013-12-02 00:00:00.000000000 Z
+dependencies:
+- !ruby/object:Gem::Dependency
+  name: nokogiri
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - '>='
+      - !ruby/object:Gem::Version
+        version: '0'
+  type: :runtime
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - '>='
+      - !ruby/object:Gem::Version
+        version: '0'
+- !ruby/object:Gem::Dependency
+  name: json
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - '>='
+      - !ruby/object:Gem::Version
+        version: '0'
+  type: :runtime
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - '>='
+      - !ruby/object:Gem::Version
+        version: '0'
+description: Libraries needed to talk to OpenNebula
+email: contact@opennebula.org
+executables: []
+extensions: []
+extra_rdoc_files: []
+files:
+- lib/opennebula.rb
+- lib/opennebula/acl.rb
+- lib/opennebula/acl_pool.rb
+- lib/opennebula/client.rb
+- lib/opennebula/cluster.rb
+- lib/opennebula/cluster_pool.rb
+- lib/opennebula/datastore.rb
+- lib/opennebula/datastore_pool.rb
+- lib/opennebula/document.rb
+- lib/opennebula/document_json.rb
+- lib/opennebula/document_pool.rb
+- lib/opennebula/document_pool_json.rb
+- lib/opennebula/error.rb
+- lib/opennebula/group.rb
+- lib/opennebula/group_pool.rb
+- lib/opennebula/host.rb
+- lib/opennebula/host_pool.rb
+- lib/opennebula/image.rb
+- lib/opennebula/image_pool.rb
+- lib/opennebula/oneflow_client.rb
+- lib/opennebula/pool.rb
+- lib/opennebula/pool_element.rb
+- lib/opennebula/system.rb
+- lib/opennebula/template.rb
+- lib/opennebula/template_pool.rb
+- lib/opennebula/user.rb
+- lib/opennebula/user_pool.rb
+- lib/opennebula/virtual_machine.rb
+- lib/opennebula/virtual_machine_pool.rb
+- lib/opennebula/virtual_network.rb
+- lib/opennebula/virtual_network_pool.rb
+- lib/opennebula/xml_element.rb
+- lib/opennebula/xml_pool.rb
+- lib/opennebula/xml_utils.rb
+- lib/opennebula/ldap_auth.rb
+- lib/opennebula/ldap_auth_spec.rb
+- lib/opennebula/server_cipher_auth.rb
+- lib/opennebula/server_x509_auth.rb
+- lib/opennebula/ssh_auth.rb
+- lib/opennebula/x509_auth.rb
+- NOTICE
+- LICENSE
+homepage: http://opennebula.org
+licenses: []
+metadata: {}
+post_install_message: 
+rdoc_options: []
+require_paths:
+- lib
+required_ruby_version: !ruby/object:Gem::Requirement
+  requirements:
+  - - '>='
+    - !ruby/object:Gem::Version
+      version: '0'
+required_rubygems_version: !ruby/object:Gem::Requirement
+  requirements:
+  - - '>='
+    - !ruby/object:Gem::Version
+      version: '0'
+requirements: []
+rubyforge_project: 
+rubygems_version: 2.0.3
+signing_key: 
+specification_version: 4
+summary: OpenNebula Client API
+test_files: []