From: Michal Fojtik <[email protected]> --- .../lib/deltacloud/drivers/rhevm/rhevm_client.rb | 521 -------------------- .../lib/deltacloud/drivers/rhevm/rhevm_driver.rb | 41 +- 2 files changed, 13 insertions(+), 549 deletions(-) delete mode 100644 server/lib/deltacloud/drivers/rhevm/rhevm_client.rb
diff --git a/server/lib/deltacloud/drivers/rhevm/rhevm_client.rb b/server/lib/deltacloud/drivers/rhevm/rhevm_client.rb deleted file mode 100644 index 5a75143..0000000 --- a/server/lib/deltacloud/drivers/rhevm/rhevm_client.rb +++ /dev/null @@ -1,521 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. The -# ASF licenses this file to you 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 'restclient' -require 'nokogiri' -require 'digest/md5' -require 'json' - -module RHEVM - - # NOTE: Injected file will be available in floppy drive inside - # the instance. (Be sure you 'modprobe floppy' on Linux) - FILEINJECT_PATH = "deltacloud-user-data.txt" - - def self.client(url) - RestClient::Resource.new(url) - end - - class BackendVersionUnsupportedException < StandardError; end - class RHEVMBackendException < StandardError - def initialize(message) - @message = message - super - end - - def message - @message - end - end - - class Client - - attr_reader :credentials, :api_entrypoint, :datacenter_id - - def initialize(username, password, api_entrypoint, datacenter_id=nil) - @credentials = { :username => username, :password => password } - @datacenter_id = datacenter_id - @api_entrypoint = api_entrypoint - end - - def vms(opts={}) - headers = { - :accept => "application/xml; detail=disks; detail=nics; detail=hosts" - } - headers.merge!(auth_header) - if opts[:id] - vm = Client::parse_response(RHEVM::client(@api_entrypoint)["/vms/%s" % opts[:id]].get(headers)).root - return [] unless current_datacenter.cluster_ids.include?((vm/'cluster').first[:id]) - [ RHEVM::VM::new(self, vm)] - else - Client::parse_response(RHEVM::client(@api_entrypoint)["/vms"].get(headers)).xpath('/vms/vm').collect do |vm| - next unless current_datacenter.cluster_ids.include?((vm/'cluster').first[:id]) - RHEVM::VM::new(self, vm) - end.compact - end - end - - def vm_action(id, action, headers={}) - headers.merge!(auth_header) - headers.merge!({:accept => 'application/xml'}) - vm = vms(:id => id) - raise RHEVMBackendException::new("Requested VM not found in datacenter #{self.current_datacenter.id}") if vm.empty? - if action==:delete - RHEVM::client(@api_entrypoint)["/vms/%s" % id].delete(headers) - else - headers.merge!({ :content_type => 'application/xml' }) - begin - client_response = RHEVM::client(@api_entrypoint)["/vms/%s/%s" % [id, action]].post('<action/>', headers) - rescue - if $!.is_a?(RestClient::BadRequest) - fault = (Nokogiri::XML($!.http_body)/'//fault/detail') - fault = fault.text.gsub(/\[|\]/, '') if fault - end - fault ||= $!.message - raise RHEVMBackendException::new(fault) - end - xml_response = Client::parse_response(client_response) - - return false if (xml_response/'action/status').first.text.strip.upcase!="COMPLETE" - end - return true - end - - def api_version?(major) - headers = { - :content_type => 'application/xml', - :accept => 'application/xml' - } - headers.merge!(auth_header) - result_xml = Nokogiri::XML(RHEVM::client(@api_entrypoint)["/"].get(headers)) - if (result_xml/'api/system_version').empty? - (result_xml/'/api/product_info/version').first[:major].strip == major - else - (result_xml/'/api/system_version').first[:major].strip == major - end - end - - def cluster_version?(cluster_id, major) - headers = { - :content_type => 'application/xml', - :accept => 'application/xml' - } - headers.merge!(auth_header) - result_xml = Nokogiri::XML(RHEVM::client(@api_entrypoint)["/clusters/%s" % cluster_id].get(headers)) - (result_xml/'/cluster/version').first[:major].strip == major - end - - def capability?(name) - headers = { - :content_type => 'application/xml', - :accept => 'application/xml' - } - headers.merge!(auth_header) - result_xml = Nokogiri::XML(RHEVM::client(@api_entrypoint)["/capabilities"].get(headers)) - !(result_xml/"/capabilities/version/custom_properties/custom_property[@name='#{name}']").empty? - end - - def create_vm(template_id, opts={}) - opts ||= {} - templ = template(template_id) - raise RHEVMBackendException::new("Requested VM not found in datacenter #{self.current_datacenter.id}") unless templ - builder = Nokogiri::XML::Builder.new do - vm { - name opts[:name] || "i-#{Time.now.to_i}" - template_(:id => template_id) - cluster_(:id => opts[:realm_id].nil? ? templ.cluster.id : opts[:realm_id]) - type_ opts[:hwp_id] || 'desktop' - memory opts[:hwp_memory] ? (opts[:hwp_memory].to_i*1024*1024).to_s : (512*1024*1024).to_s - cpu { - topology( :cores => (opts[:hwp_cpu] || '1'), :sockets => '1' ) - } - if opts[:user_data] and not opts[:user_data].empty? - if api_version?('3') and cluster_version?((opts[:realm_id] || clusters.first.id), '3') - raise "Required VDSM hook 'floppyinject' not supported by RHEV-M" unless capability?(:floppyinject) - custom_properties { - custom_property({ - :name => "floppyinject", - :value => "#{RHEVM::FILEINJECT_PATH}:#{opts[:user_data]}", - :regexp => "^([^:]+):(.*)$"}) - } - else - raise BackendVersionUnsupportedException.new - end - end - } - end - headers = opts[:headers] || {} - headers.merge!({ - :content_type => 'application/xml', - :accept => 'application/xml', - }) - templates = templates(:id => template_id) - raise RHEVMBackendException::new("Requested VM not found in datacenter #{self.current_datacenter.id}") if templates.empty? - headers.merge!(auth_header) - begin - vm = RHEVM::client(@api_entrypoint)["/vms"].post(Nokogiri::XML(builder.to_xml).root.to_s, headers) - rescue - if $!.respond_to?(:http_body) - fault = (Nokogiri::XML($!.http_body)/'/fault/detail').first - fault = fault.text.gsub(/\[|\]/, '') if fault - end - fault ||= $!.message - raise RHEVMBackendException::new(fault) - end - RHEVM::VM::new(self, Nokogiri::XML(vm).root) - end - - def create_template(vm_id, opts={}) - opts ||= {} - builder = Nokogiri::XML::Builder.new do - template_ { - name opts[:name] - description opts[:description] - vm(:id => vm_id) - } - end - headers = opts[:headers] || {} - headers.merge!({ - :content_type => 'application/xml', - :accept => 'application/xml', - }) - headers.merge!(auth_header) - template = RHEVM::client(@api_entrypoint)["/templates"].post(Nokogiri::XML(builder.to_xml).root.to_s, headers) - RHEVM::Template::new(self, Nokogiri::XML(template).root) - end - - def destroy_template(id, headers={}) - headers.merge!({ - :content_type => 'application/xml', - :accept => 'application/xml', - }) - tmpl = template(id) - raise RHEVMBackendException::new("Requested VM not found in datacenter #{self.current_datacenter.id}") unless tmpl - headers.merge!(auth_header) - RHEVM::client(@api_entrypoint)["/templates/%s" % id].delete(headers) - return true - end - - def templates(opts={}) - headers = { - :accept => "application/xml" - } - headers.merge!(auth_header) - rhevm_templates = RHEVM::client(@api_entrypoint)["/templates"].get(headers) - Client::parse_response(rhevm_templates).xpath('/templates/template').collect do |t| - next unless current_datacenter.cluster_ids.include?((t/'cluster').first[:id]) - RHEVM::Template::new(self, t) - end.compact - end - - def template(template_id) - headers = { - :accept => "application/xml" - } - headers.merge!(auth_header) - rhevm_template = RHEVM::client(@api_entrypoint)["/templates/%s" % template_id].get(headers) - RHEVM::Template::new(self, Client::parse_response(rhevm_template).root) - end - - def datacenters(opts={}) - headers = { - :accept => "application/xml" - } - headers.merge!(auth_header) - rhevm_datacenters = RHEVM::client(@api_entrypoint)["/datacenters"].get(headers) - Client::parse_response(rhevm_datacenters).xpath('/data_centers/data_center').collect do |dc| - RHEVM::DataCenter::new(self, dc) - end - end - - def clusters - current_datacenter.clusters - end - - def cluster(cluster_id) - current_datacenter.cluster(cluster_id) - end - - def current_datacenter - @current_datacenter ||= self.datacenter_id ? datacenter(self.datacenter_id) : datacenters.first - end - - def datacenter(datacenter_id) - headers = { - :accept => "application/xml" - } - headers.merge!(auth_header) - rhevm_datacenter = RHEVM::client(@api_entrypoint)["/datacenters/%s" % datacenter_id].get(headers) - RHEVM::DataCenter::new(self, Client::parse_response(rhevm_datacenter).root) - end - - def hosts(opts={}) - headers = { - :accept => "application/xml" - } - headers.merge!(auth_header) - if opts[:id] - vm = Client::parse_response(RHEVM::client(@api_entrypoint)["/hosts/%s" % opts[:id]].get(headers)).root - [ RHEVM::Host::new(self, vm)] - else - Client::parse_response(RHEVM::client(@api_entrypoint)["/hosts"].get(headers)).xpath('/hosts/host').collect do |vm| - RHEVM::Host::new(self, vm) - end - end - end - - def storagedomains(opts={}) - headers = { - :accept => "application/xml" - } - headers.merge!(auth_header) - if opts[:id] - vm = Client::parse_response(RHEVM::client(@api_entrypoint)["/storagedomains/%s" % opts[:id]].get(headers)).root - [ RHEVM::StorageDomain::new(self, vm)] - else - Client::parse_response(RHEVM::client(@api_entrypoint)["/storagedomains"].get(headers)).xpath('/storage_domains/storage_domain').collect do |vm| - RHEVM::StorageDomain::new(self, vm) - end - end - end - - def auth_header - # As RDOC says this is the function for strict_encode64: - encoded_credentials = ["#{@credentials[:username]}:#{@credentials[:password]}"].pack("m0").gsub(/\n/,'') - { :authorization => "Basic " + encoded_credentials } - end - - def base_url - url = URI.parse(@api_entrypoint) - "#{url.scheme}://#{url.host}:#{url.port}" - end - - def self.parse_response(response) - Nokogiri::XML(response) - end - - def has_datacenter?(vm) - value=!(vm/'data_center').empty? - value - end - end - - class BaseObject - attr_accessor :id, :href, :name - attr_reader :client - - def initialize(client, id, href, name) - @id, @href, @name = id, href, name - @client = client - self - end - end - - class Link - attr_accessor :id, :href, :client - - def initialize(client, id, href) - @id, @href = id, href - @client = client - end - - def follow - xml = Client::parse_response(RHEVM::client(@client.base_url)[@href].get(@client.auth_header)) - object_class = ::RHEVM.const_get(xml.root.name.camelize) - object_class.new(@client, (xml.root)) - end - - end - - class VM < BaseObject - attr_reader :description, :status, :memory, :profile, :display, :host, :cluster, :template, :macs - attr_reader :storage, :cores, :username, :creation_time - attr_reader :ip, :vnc - - def initialize(client, xml) - super(client, xml[:id], xml[:href], (xml/'name').first.text) - @username = client.credentials[:username] - parse_xml_attributes!(xml) - self - end - - private - - def parse_xml_attributes!(xml) - @description = ((xml/'description').first.text rescue '') - @status = (xml/'status').first.text - @memory = (xml/'memory').first.text - @profile = (xml/'type').first.text - @template = Link::new(@client, (xml/'template').first[:id], (xml/'template').first[:href]) - @host = Link::new(@client, (xml/'host').first[:id], (xml/'host').first[:href]) rescue nil - @cluster = Link::new(@client, (xml/'cluster').first[:id], (xml/'cluster').first[:href]) - @display = { - :type => (xml/'display/type').first.text, - :address => ((xml/'display/address').first.text rescue nil), - :port => ((xml/'display/port').first.text rescue nil), - :monitors => (xml/'display/monitors').first.text - } - @cores = ((xml/'cpu/topology').first[:cores] rescue nil) - @storage = ((xml/'disks/disk/size').first.text rescue nil) - @macs = (xml/'nics/nic/mac').collect { |mac| mac[:address] } - @creation_time = (xml/'creation_time').text - @ip = ((xml/'guest_info/ips/ip').first[:address] rescue nil) - @vnc = { - :address => ((xml/'display/address').first.text rescue "127.0.0.1"), - :port => ((xml/'display/port').first.text rescue "5890") - } unless @ip - end - - end - - class Template < BaseObject - attr_reader :description, :status, :cluster - - def initialize(client, xml) - super(client, xml[:id], xml[:href], (xml/'name').first.text) - parse_xml_attributes!(xml) - self - end - - private - - def parse_xml_attributes!(xml) - @description = ((xml/'description').first.text rescue nil) - @status = (xml/'status').first.text - @cluster = Link::new(@client, (xml/'cluster').first[:id], (xml/'cluster').first[:href]) - end - end - - class Cluster < BaseObject - attr_reader :description, :datacenter, :version - - def initialize(client, xml) - super(client, xml[:id], xml[:href], (xml/'name').first.text) - parse_xml_attributes!(xml) - self - end - - private - - def parse_xml_attributes!(xml) - @description = ((xml/'description').first.text rescue nil) - @version =((xml/'version').first[:major].strip rescue nil) - unless (xml/'data_center').empty? - @datacenter = Link::new(@client, (xml/'data_center').first[:id], (xml/'data_center').first[:href]) - end - end - - end - - class DataCenter < BaseObject - attr_reader :description, :status - - def initialize(client, xml) - super(client, xml[:id], xml[:href], (xml/'name').first.text) - parse_xml_attributes!(xml) - self - end - - def clusters - headers = { - :accept => "application/xml; detail=datacenters" - } - headers.merge!(client.auth_header) - clusters_list = RHEVM::client(client.api_entrypoint)["/clusters"].get(headers) - cluster_arr = Client::parse_response(clusters_list).xpath('/clusters/cluster') - clusters_arr = [] - cluster_arr.each do |cluster| - cluster = RHEVM::Cluster.new(self.client, cluster) - clusters_arr << cluster if cluster.datacenter && cluster.datacenter.id == client.datacenter_id - end - clusters_arr - end - - def cluster(cluster_id) - headers = { - :accept => "application/xml; detail=datacenters" - } - headers.merge!(client.auth_header) - cluster_xml = RHEVM::client(client.api_entrypoint)["/clusters/%s" % cluster_id].get(headers) - cluster = RHEVM::Cluster.new(self.client, cluster_xml) - if cluster.datacenter && cluster.datacenter.id == client.datacenter_id - cluster - else - nil - end - end - - def cluster_ids - @cluster_ids ||= clusters.collect { |c| c.id } - end - - private - - def parse_xml_attributes!(xml) - @description = ((xml/'description').first.text rescue nil) - @status = (xml/'status').first.text - end - end - - class Host < BaseObject - attr_reader :description, :status, :cluster - - def initialize(client, xml) - super(client, xml[:id], xml[:href], (xml/'name').first.text) - parse_xml_attributes!(xml) - self - end - - private - - def parse_xml_attributes!(xml) - @description = ((xml/'description').first.text rescue nil) - @status = (xml/'status').first.text - @clister = Link::new(@client, (xml/'cluster').first[:id], (xml/'cluster').first[:href]) - end - end - - class StorageDomain < BaseObject - attr_reader :available, :used, :kind, :address, :path - - def initialize(client, xml) - super(client, xml[:id], xml[:href], (xml/'name').first.text) - parse_xml_attributes!(xml) - self - end - - private - - def parse_xml_attributes!(xml) - @available = (xml/'available').first.text - @used = (xml/'used').first.text - @kind = (xml/'storage/type').first.text - @address = ((xml/'storage/address').first.text rescue nil) - @path = ((xml/'storage/path').first.text rescue nil) - end - end - -end - -class String - unless method_defined?(:camelize) - # Camelize converts strings to UpperCamelCase - def camelize - self.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } - end - end -end diff --git a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb index a66b9c6..e46642e 100644 --- a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +++ b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb @@ -14,18 +14,8 @@ # License for the specific language governing permissions and limitations # under the License. -# Minihowto: Setting up this driver -# -# 1. Setup RHEV-M server -# 2. Setup RHEV-M API (git://git.fedorahosted.org/rhevm-api.git - follow README) -# 3. Set URL to API using shell variable (or HTTP header, see comment on provider_url) -# export API_PROVIDER="https://x.x.x.x/rhevm-api-powershell" -# 4. Start Deltacloud using: deltacloudd -i rhevm -# 5. Use RHEV-M credentials + append Windows Domain -# like: [email protected] - require 'deltacloud/base_driver' -require 'deltacloud/drivers/rhevm/rhevm_client' +require 'rbovirt' module Deltacloud module Drivers @@ -187,23 +177,18 @@ class RHEVMDriver < Deltacloud::BaseDriver def create_instance(credentials, image_id, opts={}) client = new_client(credentials) params = {} - name = opts[:name] - if not name - name = Time.now.to_i.to_s - end - if name.length > USER_NAME_MAX - raise "Parameter name must be #{USER_NAME_MAX} characters or less" + if opts[:name] + raise "Parameter name must be #{USER_NAME_MAX} characters or less" if opts[:name].length > USER_NAME_MAX end safely do - params[:name] = name - params[:realm_id] = opts[:realm_id] if opts[:realm_id] + params[:name] = opts[:name] + params[:template] = opts[:image_id] + params[:cluster] = opts[:realm_id] if opts[:realm_id] params[:hwp_id] = opts[:hwp_id] if opts[:hwp_id] - params[:hwp_memory] = opts[:hwp_memory] if opts[:hwp_memory] - params[:hwp_cpu] = opts[:hwp_cpu] if opts[:hwp_cpu] - if opts[:user_data] - params[:user_data] = opts[:user_data].gsub(/\n/,'') - end - convert_instance(client, client.create_vm(image_id, params)) + params[:memory] = opts[:hwp_memory] if opts[:hwp_memory] + params[:cores] = (opts[:hwp_cpu].to_i * 1024) if opts[:hwp_cpu] + params[:user_data] = opts[:user_data].gsub(/\n/,'') if opts[:user_data] + convert_instance(client, client.create_vm(params)) end end @@ -224,7 +209,7 @@ class RHEVMDriver < Deltacloud::BaseDriver def new_client(credentials) url, datacenter = api_provider.split(';') safely do - ::RHEVM::Client.new(credentials.user, credentials.password, url, datacenter) + OVIRT::Client.new(credentials.user, credentials.password, url, datacenter) end end @@ -260,7 +245,7 @@ class RHEVMDriver < Deltacloud::BaseDriver end # If IP retrieval failed, fallback to VNC and MAC address if public_addresses.empty? - public_addresses = inst.macs.collect { |mac_address| InstanceAddress.new(mac_address, :type => :mac) } + public_addresses = inst.interfaces.map { |interface| InstanceAddress.new(interface.mac, :type => :mac) } end if inst.vnc public_addresses << InstanceAddress.new(inst.vnc[:address], :port => inst.vnc[:port], :type => :vnc) @@ -271,7 +256,7 @@ class RHEVMDriver < Deltacloud::BaseDriver :state => state, :image_id => inst.template.id, :realm_id => inst.cluster.id, - :owner_id => inst.username, + :owner_id => client.credentials[:username], :launch_time => inst.creation_time, :instance_profile => profile, :hardware_profile_id => profile.id, -- 1.7.8.2
