Skip to content

Commit

Permalink
edits 6-Jan-2017
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter McGowan committed Jan 6, 2017
1 parent 66b8d78 commit 552c568
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 61 deletions.
4 changes: 2 additions & 2 deletions evm_and_the_workspace/chapter.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ $evm.root['instance'] = object_walker (type: String)

As we saw, `$evm.root` returns to us the object representing the instance that was launched when we entered Automate. Many instances have schemas that contain relationships to other instances, and as each relationship is followed, a new child object is created under the calling object to represent the called instance. These objects all live in the same workspace, they share the same `$evm` variable. Fortunately we can access any of the objects in this parent-child hierarchy using `$evm.object`.

Calling `$evm.object` with no arguments returns the currently instantiated/running instance. As automation scripters we can think of this as "our currently running code", and we can access it using the alias `$evm.current`. When we wanted to access our schema variable __username__, we accessed it using `$evm.object['username']`.
Calling `$evm.object` with no arguments returns the currently instantiated/running instance. As automation scripters we can think of this as "our currently running code", and we can also access it using the alias `$evm.current`. When we wanted to access our 'username' schema variable in link:../using_schema_variables/chapter.asciidoc[Using Schema Variables], we accessed it using `$evm.object['username']`.

We can access our parent object (the one that called us) using `$evm.object("..")`, or the alias `$evm.parent`.

Expand Down Expand Up @@ -195,7 +195,7 @@ We can use `$evm.instantiate` to launch another Automate instance programmatical

[source,ruby]
----
$evm.instantiate('/Discovery/Methods/ObjectWalker')
$evm.instantiate('/Discovery/ObjectWalker/object_walker')
----

Instances called in this way execute synchronously, so the calling method waits for completion before continuing. The called instance also appears as a child object of the caller (it sees the caller as its `$evm.parent`).
Expand Down
10 changes: 5 additions & 5 deletions introduction/chapter.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Infrastructure providers enable us to manage three traditional infrastructure pr

==== Container Providers

Container providers allow us to connect to and manage Docker container managers. CloudForms 4.2 supports OpenShift Container Platform as a container manager, but ManageIQ _Euwe_ also adds Kubernetes and OpenShift Origin as available managers.
Container providers allow us to connect to and manage Docker container managers. CloudForms 4.2 supports OpenShift Container Platform as a container manager, but ManageIQ _Euwe_ also adds Kubernetes and OpenShift Origin as available managers.

==== Configuration Management Providers

Expand Down Expand Up @@ -126,15 +126,15 @@ We can create self-service catalogs to permit users to order our orchestration w

As an extension of its Automate capability, CloudForms and ManageIQ are able to connect to and _Integrate_ with many Enterprise tools and systems. Both systems come with Ruby Gems to enable automation scripts to connect to both RESTful and SOAP APIs, as well as libraries to connect to several SQL and LDAP databases, and the ability to run remote PowerShell scripts on Windows servers.

Typical integration actions might be to extend the virtual machine provisioning workflow to retrieve and use an IP address from a corporate IP address management (IPAM) solution; to create a new cconfiguration item (CI) record in the central configuration management database (CMDB), or to create and update tickets in the enterprise Service Management tool, such as ServiceNow.
Typical integration actions might be to extend the virtual machine provisioning workflow to retrieve and use an IP address from a corporate IP address management (IPAM) solution; to create a new configuration item (CI) record in the central configuration management database (CMDB), or to create and update tickets in the enterprise Service Management tool, such as ServiceNow.

=== The Appliance

To simplify installation, both CloudForms are ManageIQ are distributed as fully installed virtual machine templates, often just referred to as _Appliances_ for convenience. An appliance comes pre-configured with everything we need. A CloudForms 4.2 appliance runs RHEL 7.3 (CentOS 7.3 in the case of ManageIQ (Euwe_)), with PostgreSQL 9.5, Rails 5.0.0.1, the CloudForms/ManageIQ application, and all associated Ruby gems installed. Appliances are downloadable as a virtual machine image template in formats suitable for VMware, Red Hat Enterprise Virtualization, OpenStack, Amazon EC2, Microsoft's System Center Virtual Machine Manager or Azure cloud, and Google Compute Engine. They are also available as a Docker container image.

==== Ruby and Rails

The core "evmserverd" application is witten in Ruby on Rails, and uses PostgreSQL as its database. When we use the Automate capability of CloudForms or ManageIQ we work extensively with the Ruby language, and write scripts that interact with a Ruby object model defined for us by the Automation Engine. We certainly don't need to be Rails developers however (we don't really _need_ to know anything about Rails), but as we'll see in <<peeping-under-the-hood>>, some understanding of Rails concepts can make it easier to understand the object model, and what happens behind the scenes when we run our scripts.
The core "evmserverd" application is witten in Ruby on Rails, and uses PostgreSQL as its database. When we use the Automate capability of CloudForms or ManageIQ we work extensively with the Ruby language, and write scripts that interact with a Ruby object model defined for us by the Automation Engine. We certainly don't need to be Rails developers however (we don't really _need_ to know anything about Rails), but as we'll see in link:../../peeping_under_the_hood/chapter.asciidoc[Peeping Under the Hood], some understanding of Rails concepts can make it easier to understand the object model, and what happens behind the scenes when we run our scripts.

[NOTE]
Why Rails? Ruby on Rails is a powerful development framework for database-centric web-based applications. It is popular for open source product development, for example _Foreman_, one of the core components of Red Hat's _Satellite 6.x_ product, is also a Rails application.
Expand All @@ -145,7 +145,7 @@ Red Hat is an open source company, and its _products_ are derived from one or mo

==== ManageIQ (the _Project_)

The ManageIQ project releases a new version every six months (approximately). Each version is named alphabetically after a chess Grand Master, and so far these have been Anand, Botvinnik, Capablanca, and Darga. At the time of writing, Darga is the current stable release, and Euwe is in development.
The ManageIQ project releases a new version every six months (approximately). Each version is named alphabetically after a chess Grand Master, and so far these have been Anand, Botvinnik, Capablanca, Darga and Euwe. At the time of writing, Euwe is the current stable release, and Fine is in development.

==== Red Hat CloudForms (the _Product_)

Expand All @@ -169,7 +169,7 @@ _CloudForms Management Engine_ is the name of the CloudForms virtual appliance t
|Botvinnik|13 - 22|5.4|3.2
|Capablanca|23 - 33|5.5|4.0
|Darga|34 - 42|5.6|4.1
|Euwe| 43 -|5.7|4.2
|Euwe| 43 - 51|5.7|4.2
|=======

=== Summary
Expand Down
38 changes: 15 additions & 23 deletions introduction_to_the_automate_datastore/chapter.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -168,31 +168,23 @@ A _method_ is a self-contained block of Ruby code that gets executed when we run

[source,ruby]
....
###################################################################
#
# Description: This method checks to see if the VM has been powered off or
# suspended
# Description: select the cloud network
# Default availability zone is provided by Openstack
#
# Get vm from root object
vm = $evm.root['vm']
if vm
power_state = vm.attributes['power_state']
ems = vm.ext_management_system
$evm.log('info', "VM:<#{vm.name}> on provider:<#{ems.try(:name)} has Power \
State:<#{power_state}>")
# If VM is powered off or suspended exit
if %w(off suspended).include?(power_state)
# Bump State
$evm.root['ae_result'] = 'ok'
elsif power_state == "never"
# If never then this VM is a template so exit the retirement state machine
$evm.root['ae_result'] = 'error'
else
$evm.root['ae_result'] = 'retry'
$evm.root['ae_retry_interval'] = '60.seconds'
###################################################################
# Get variables
prov = $evm.root["miq_provision"]
image = prov.vm_template
raise "Image not specified" if image.nil?
if prov.get_option(:cloud_network).nil?
cloud_network = prov.eligible_cloud_networks.first
if cloud_network
prov.set_cloud_network(cloud_network)
$evm.log("info", "Image=[#{image.name}] Cloud Network=[#{cloud_network.name}]")
end
end
....
Expand Down
Binary file modified introduction_to_the_automate_datastore/images/ss1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified introduction_to_the_automate_datastore/images/ss1.psd
Binary file not shown.
60 changes: 29 additions & 31 deletions tower_related_automate_components/chapter.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -79,54 +79,52 @@ The method exits with `$evm.root['ae_result']` set to 'error', 'retry' or 'ok' a

We can easily run an Ansible Tower job template on any virtual machine from an Automate method.

In this example we'll run a job template called 'Install Single Package' on a VM called 'testserver02'. We'll pass to the job template the extra variable 'package_name' with the value 'screen'. For the example use-case the code snippet is not running as part of a provisioning operation, nor called from a button on the VM in the WebUI. It therefore must load the VM object into `$evm.root['vm']` itself.
In this example we'll run a job template called 'Install Single Package' on a VM called 'testserver'. We'll pass to the job template the extra variable 'package_name' with the value 'screen'. To prevent a long-running Ansible playbook from timing out our currently running method, we'll launch the AnsibleTower state machine as a new automation request, rather than using `$evm.instantiate`. As the new method will not running as part of a provisioning operation, nor called from a button on the VM in the WebUI, we must ensure that the VM object is loaded into `$evm.root['vm']` at runtime. We do this by passing a "Vm:vm" argument containing the VM object ID that we wish to load, as shown in the following code:

[source,ruby]
----
PATH = '/ConfigurationManagement/AnsibleTower/Operations/StateMachines/Job/default'.freeze
SCRIPT_CLASS = 'ManageIQ_Providers_AnsibleTower_ConfigurationManager_ConfigurationScript'.freeze
ANSIBLE_NAMESPACE = 'ConfigurationManagement/AnsibleTower/Operations/StateMachines'.freeze
ANSIBLE_STATE_MACHINE_CLASS = 'Job'.freeze
ANSIBLE_STATE_MACHINE_INSTANCE = 'default'.freeze
VM_CLASS = 'VmOrTemplate'.freeze
attrs = {}
attrs['job_template_name'] = 'Install Single Package'
attrs['dialog_param_package_name'] = 'screen'
#
# Lookup the job template object and attach as $evm.object['job_template']
#
$evm.object['job_template'] = $evm.vmdb(SCRIPT_CLASS).find_by_name('Install Single Package')
#
# Lookup the VM object and attach as $evm.root['vm']
#
$evm.root['vm'] = $evm.vmdb(VM_CLASS).find_by_name('testserver02')
# Passing an attribute of Vm::vm=id ensures that the executed method will
# have $evm.root['vm'] pre-loaded with the VM with this ID
#
# Power on the VM of it's not already on
vm = $evm.vmdb(VM_CLASS).find_by_name('testserver')
attrs['Vm::vm'] = vm.id
#
$evm.root['vm'].start if $evm.root['vm'].power_state != 'on'
# make sure the VM is started
#
# Define our URI to call the state machine, including the extra_var as an argument
vm.start if vm.power_state != 'on'
#
uri = "#{PATH}?param1=package_name%3Dscreen"
# Call the job template as a new automation request in case it runs for
# longer than 10 minutes
#
# Call the state machine
#
$evm.instantiate(uri)
options = {}
options[:namespace] = ANSIBLE_NAMESPACE
options[:class_name] = ANSIBLE_STATE_MACHINE_CLASS
options[:instance_name] = ANSIBLE_STATE_MACHINE_INSTANCE
options[:user_id] = $evm.root['user'].id
options[:attrs] = attrs
auto_approve = true
$evm.execute('create_automation_request', options, $evm.root['user'].userid, auto_approve)
----

Rather than looking up the `SCRIPT_CLASS` object and attaching that to `$evm.object['job_template']`, we could have passed the job template name as an argument in the URI, for example:
Rather than passing the attribute 'job_template_name', we could if we wish pass 'job_template_id'. For example we may have been passed the template ID from a service dialog, or we may have multiple Ansible Tower providers with duplicate job template names, and wish to identify the correct template. The following code shows how we would lookup and specify the job template ID for a job template on a particular provider (in this case the provider has the ID of 4):

[source,ruby]
----
uri = "#{PATH}?job_template_name=Install%20Single%20Package&param1=package_name%3Dscreen"
----

Using the alternative syntax for argument passing, we could re-write this as follows:

[source,ruby]
----
uri = "#{PATH}?job_template_name=Install%20Single%20Package&dialog_param_package_name=screen"
SCRIPT_CLASS = 'ManageIQ_Providers_AnsibleTower_ConfigurationManager_ConfigurationScript'.freeze
job_template = $evm.vmdb(SCRIPT_CLASS).where(
["manager_id = ? AND name = ?", 4, 'Install Single Package']
).first
attrs['job_template_id'] = job_template.id
----

[NOTE]
====
If our URI contains reserved or unsafe characters, we must URL-encode them. In these examples we have replaced ' ' with '%20' and '=' with '%3D'
====

==== Calling the State Machine from an Instance

We can call the _Job/default_ state machine directly from a relationship in an instance, and even pass extra variable arguments from schema attributes. This gives us the flexibility to be able to combine Ruby methods and Ansible playbooks in a single instance if we wish (see <<i3>>).
Expand Down

0 comments on commit 552c568

Please sign in to comment.