Skip to content

Commit

Permalink
Update some links to the scripts directories, and provider a RHV 4.x …
Browse files Browse the repository at this point in the history
…compatible add_disk script
  • Loading branch information
Peter McGowan committed Jan 24, 2018
1 parent 97655ee commit 01355b7
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 4 deletions.
2 changes: 1 addition & 1 deletion automation_request_approval/chapter.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ image::images/ss6.png[Screenshot,350,align="center"]
The method code is copied and adapted as appropriate from the VM _ProvisionRequest_Pending_ method. We specify as the *to_email_address* a user that will act as approver for the automation requests.

The full code for the methods is
https://github.com/pemcg/oreilly-mastering-cloudforms-automation/tree/master/chapter43/scripts[here]
https://github.com/pemcg/mastering-automation-in-cloudforms-4.2-and-manageiq-euwe/tree/master/automation_request_approval/scripts[here]

=== Policies

Expand Down
11 changes: 8 additions & 3 deletions customising_vm_provisioning/chapter.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ In link:../vm_provision_state_machine/chapter.asciidoc[The VM Provision State Ma

=== Scenario

We are using an RHEV provider with our ManageIQ installation, and we can successfully provision virtual machines using *Native Clone* provision type from fully configured RHEV templates. The templates all have a single 30GB thin-provisioned hard drive.
We are using an RHEV 3.6 provider with our ManageIQ installation, and we can successfully provision virtual machines using *Native Clone* provision type from fully configured RHEV templates. The templates all have a single 30GB thin-provisioned hard drive.

[NOTE]
====
This chapter makes API calls to the RHEV manager using the RHEV 3.x API payload syntax. This has changed slightly with RHV 4.x, and these examples do not work correctly with RHV 4.x. A RHV 4.x compatible __add_disk__ script is provided https://github.com/pemcg/mastering-automation-in-cloudforms-4.2-and-manageiq-euwe/tree/master/customising_vm_provisioning/scripts/add_disk_rhv_4x.rb[here]
====

=== Task

We would like all virtual machines provisioned from these templates to have a second 30GB hard drive added automatically during provisioning. The second drive should be created in the same RHEV storage domain as the first drive, (i.e. not hardcoded to a storage domain).
We would like all virtual machines provisioned from these templates to have a second 30GB hard drive added automatically during provisioning. The second drive should be created in the same RHEV storage domain as the first drive, (i.e. not hard coded to a storage domain).

=== Methodology

Expand Down Expand Up @@ -298,7 +303,7 @@ rescue => err
end
----

The full scripts are also available from https://github.com/pemcg/oreilly-mastering-cloudforms-automation[here]
The full scripts are also available from https://github.com/pemcg/mastering-automation-in-cloudforms-4.2-and-manageiq-euwe/tree/master/customising_vm_provisioning/scripts[here]

==== Step 4. Add Our New Instances to the Copied State Machine

Expand Down
176 changes: 176 additions & 0 deletions customising_vm_provisioning/scripts/add_disk_rhv_4x.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# ------------------------------------------------------------------------------
#
# CFME Automate Method: add_disk
#
# Authors: Kevin Morey, Peter McGowan (Red Hat)
# Update: Razique Mahroua (Red Hat) - Makes it compatible with RHV 4 API
# Notes: This method adds a disk to a RHEV VM
#
# ------------------------------------------------------------------------------

require 'rest_client'
require 'nokogiri'

NEW_DISK_SIZE = 10
@debug = false

begin

def call_rhev(servername, username, password, action, ref=nil, body_type=:xml, body=nil)
#
# If ref is a url then use that one instead
#
unless ref.nil?
url = ref if ref.include?('http')
end
url ||= "https://#{servername}#{ref}"

params = {
:method => action,
:url => url,
:user => username,
:password => password,
:headers => { :content_type=>body_type, :accept=>:xml },
:verify_ssl => false
}
params[:payload] = body if body
if @debug
$evm.log(:info, "Calling RHEVM at: #{url}")
$evm.log(:info, "Action: #{action}")
$evm.log(:info, "Payload: #{params[:payload]}")
end
rest_response = RestClient::Request.new(params).execute
#
# RestClient raises an exception for us on any non-200 error
#
return rest_response
end


#
# Start of main code
#
case $evm.root['vmdb_object_type']
when 'miq_provision' # called from a VM provision workflow
vm = $evm.root['miq_provision'].destination
disk_size_bytes = NEW_DISK_SIZE * 1024**3
when 'vm'
vm = $evm.root['vm'] # called from a button
disk_size_bytes = $evm.root['dialog_disk_size_gb'].to_i * 1024**3
end

storage_id = vm.storage_id rescue nil
$evm.log(:info, "VM Storage ID: #{storage_id}") if @debug
#
# Extract the RHEV-specific Storage Domain ID
#
unless storage_id.nil? || storage_id.blank?
storage = $evm.vmdb('storage').find_by_id(storage_id)
storage_domain_id = storage.ems_ref.match(/.*\/(\w.*)$/)[1]
if @debug
$evm.log(:info, "Found Storage: #{storage.name}")
$evm.log(:info, "ID: #{storage.id}")
$evm.log(:info, "ems_ref: #{storage.ems_ref}")
$evm.log(:info, "storage_domain_id: #{storage_domain_id}")
end
end

unless storage_domain_id.nil?
#
# Extract the IP address and credentials for the RHEV Provider
#
servername = vm.ext_management_system.ipaddress || vm.ext_management_system.hostname
username = vm.ext_management_system.authentication_userid
password = vm.ext_management_system.authentication_password

builder = Nokogiri::XML::Builder.new do |xml|
xml.disk_attachment {
xml.bootable 'false'
xml.interface 'virtio'
xml.active 'true'
xml.disk {
xml.format 'cow'
xml.name 'disk2'
xml.provisioned_size disk_size_bytes
xml.storage_domains {
xml.storage_domain :id => storage_domain_id
}
}
}
end

body = builder.to_xml
$evm.log(:info, "Adding #{disk_size_bytes / 1024**3} GByte disk to VM: #{vm.name}")
response = call_rhev(servername, username, password, :post, "/ovirt-engine"+"#{vm.ems_ref}/diskattachments", :xml, body)
#
# Parse the response body XML
#
doc = Nokogiri::XML.parse(response.body)
#
# Pull out some re-usable href's from the initial response
#
creation_status_href = doc.at_xpath("/disk_attachment/link")['href']
disk_href = doc.at_xpath("/disk_attachment/disk")['href']
attachment_href = doc.at_xpath("/disk_attachment")['href']

# activate_href = doc.at_xpath("/disk/actions/link[@rel='activate']")['href']
if @debug
$evm.log(:info, "creation_status_href: #{creation_status_href}")
$evm.log(:info, "disk_href: #{disk_href}")
$evm.log(:info, "attachment_href: #{attachment_href}")
# $evm.log(:info, "activate_href: #{activate_href}")
end
#
# Validate the creation_status (wait for up to a minute)
#
creation_status = doc.at_xpath("/disk_attachment/creation_status").text
counter = 13
$evm.log(:info, "Creation Status: #{creation_status}")
while creation_status != "ok"
counter -= 1
if counter == 0
raise "Timeout waiting for new disk creation_status to reach \"complete\": \
Creation Status = #{creation_status}"
else
sleep 5
response = call_rhev(servername, username, password, :get, disk_href, :xml, nil)
doc = Nokogiri::XML.parse(response.body)
creation_status = doc.at_xpath("/disk/status").text
$evm.log(:info, "Creation Status: #{creation_status}")
end
end

#
# Disk has been created successfully,
# now check its activation status and if necessary activate it
#
response = call_rhev(servername, username, password, :get, attachment_href, :xml, nil)
doc = Nokogiri::XML.parse(response.body)
if doc.at_xpath("/disk_attachment/active").text != "true"
$evm.log(:info, "Activating disk")
body = "<action/>"
response = call_rhev(servername, username, password, :post, activate_href, :xml, body)
else
$evm.log(:info, "New disk already active")
end
end
#
# Exit method
#
$evm.root['ae_result'] = 'ok'
exit MIQ_OK
#
# Set Ruby rescue behavior
#
rescue RestClient::Exception => err
$evm.log(:error, "The REST request failed with code: #{err.response.code}") unless err.response.nil?
$evm.log(:error, "The response body was:\n#{err.response.body.inspect}") unless err.response.nil?
$evm.root['ae_reason'] = "The REST request failed with code: #{err.response.code}" unless err.response.nil?
$evm.root['ae_result'] = 'error'
exit MIQ_STOP
rescue => err
$evm.log(:error, "[#{err}]\n#{err.backtrace.join("\n")}")
$evm.root['ae_reason'] = "Unspecified error, see automation.log for backtrace"
$evm.root['ae_result'] = 'error'
exit MIQ_STOP
end

0 comments on commit 01355b7

Please sign in to comment.