BEYOND AEM CURL COMMANDS
Cliffano Subagio (@cliffano) - Shine Solutions - Adobe Immerse’18

SHINE SOLUTIONS https://shinesolutions.com
AEM Community Solution Partner
AEM applications and cloud infrastructure projects since 2013
CLIFFANO SUBAGIO cliff.subagio@shinesolutions.com
Senior Consultant
Creator of AEM OpenCloud
AGENDA
1. Introduction + history
2. The problems with curl commands
3. API clients as the solution
4. Current and future use cases
5. What’s next?
Introduction
cURL is everywhere!
This looks harmless…
curl 
-u admin:admin 
-F package=@“my-aem-package.zip” 
http://localhost:4502/crx/packmgr/service/.json/?cmd=upload
But this looks harmful…
set -o errexit
result=$(curl … )
if [[ $result = *”error” ]]; then
exit 123
fi
Fragile error checking
Uninformative error result
Unreliable exit code
No success result
Create
Machine Images
Create
AEM Environment
Run
Regression Tests
Deploy
Applications
Build Pipeline
~5mins~40mins
~20mins ~30mins
Only allows less than 6 pipeline runs per day!
curl commands
used here
cURL command error identified at the end
Everyone felt unproductive
Project Manager
Operations
Developers
Testers
Security
Everyone felt unproductive
The problems
Problem 1:
cURL commands everywhere
For everything
Problem 2:
Inconsistent response payload types
JSON Example - Get install status
{
“status":
{
“finished": true,
“itemCount": 0
}
}
XML Example - Listing packages
<crx version="1.4.1" user="admin" workspace="crx.default">
<request>
<param name="cmd" value="ls"/>
</request>
<response>
<data>
<packages>
<package>
<group>Adobe/granite</group>
<name>com.adobe.granite.httpcache.content</name>
<version>1.0.2</version>
<downloadName>com.adobe.granite.httpcache.content-1.0.2.zip</downloadName>
<size>13323</size>
<created>Tue, 25 Feb 2014 10:40:56 +0000</created>
<createdBy>Adobe</createdBy>
<lastModified></lastModified>
<lastModifiedBy>null</lastModifiedBy>
<lastUnpacked>Tue, 5 Jun 2018 01:15:49 +0000</lastUnpacked>
<lastUnpackedBy>admin</lastUnpackedBy>
</package>
…
HTML Example - Creating a user
<html>
<head>
<title>Content created /home/users/s/nWkLPRxMJe5WwsySVrnv</title>
</head>
<body>
<h1>Content created /home/users/s/nWkLPRxMJe5WwsySVrnv</h1>
<table>
<tbody>
<tr>
<td>Status</td>
<td><div id="Status">201</div></td>
</tr>
<tr>
<td>Message</td>
<td><div id="Message">Created</div></td>
</tr>
…
<tr>
<td>Path</td>
<td><div id="Path">/home/users/s/nWkLPRxMJe5WwsySVrnv</div></td>
</tr>
…
Problem 3:
Unreliable status codes
(intermittent) Error 401
on package upload success
{
“success”:true,
"msg":"Package uploaded”,
“path”:”/etc/packages/path/my-package-1.0.zip"
}
Success 200
on change user password error
• http 200 with empty response body

when authentication is invalid
• http 200 with error message in html response body

when old password is incorrect
Problem 4:
What if there’s no shell?
Think serverless!
Problem 5:
Lack of integration with
various technology stacks
The solution
Swagger AEM
• API specification for AEM endpoints
• Swagger/OpenAPI version 2
• Swagger CodeGenerator -> OpenAPI Generator
• Ruby, Python, Java, and JavaScript API clients
• https://github.com/shinesolutions/swagger-aem/
•
OpenAPI Specification
/crx/packmgr/service/.json/{path}:
post:
operationId: postPackageServiceJson
produces:
- application/json
parameters:
- name: path
in: path
required: true
type: string
- name: cmd
in: query
required: true
type: string
- name: groupName
in: query
required: false
type: string
- name: packageName
in: query
required: false
type: string
- name: packageVersion
in: query
required: false
type: string
- name: _charset_
in: query
required: false
type: string
- name: force
in: query
required: false
type: boolean
- name: recursive
in: query
required: false
type: boolean
- name: package
in: formData
required: false
type: file
consumes:
- multipart/form-data
responses:
default:
description: 'Default response'
schema:
type: string
tags:
- crx
Ruby AEM
• Resource oriented design
• Further abstraction away from AEM endpoints
• Error and response objects
• Additional custom APIs
• https://github.com/shinesolutions/ruby_aem
•
Result Handling
package = aem.package('somepackagegroup', 'somepackage', '1.2.3')
opts = { force: true }
result = package.upload('/tmp', opts)
puts result.message
puts result.response.status_code
puts result.response.body
puts result.response.headers
puts result.data
Error Handling
begin
rescue RubyAem::Error => err
end
package = aem.package('somepackagegroup', 'somepackage', '1.2.3')
opts = { force: true }
result = package.upload('/tmp', opts)
puts err.message
puts err.result.response.status_code
puts err.result.response.body
puts err.result.response.headers
puts err.result.data
Problems Solved
No dependency to shell, cloud functions ready
Response objects, JSON/XML/HTML included
Better status handling, http status code included
Easier to integrate with various technologies
First class language, not just cURL commands
Features
• Wait until login page is ready
• Wait until AEM health check is passed
• Bundle start, stop
• Configuration property create
• Replication, reverse replication, and flush agents create, update,
delete
• User and group create and delete
• Add user and group to a group
• Node create and delete
• Package create, update, delete, upload, install, uninstall,
replicate, list, versions
• Path activate
• Repository block, unblock
Use cases
Puppet AEM Resources
• Puppet module for provisioning AEM resources
• Written on top of ruby_aem
• Puppet debug mode support
• https://github.com/shinesolutions/puppet-aem-
resources
•
Example Usage
aem_package { 'Install AEM6.2 hotfix 12785':
ensure => present,
name => 'cq-6.2.0-hotfix-12785',
group => 'adobe/cq620/hotfix',
version => '7.0',
path => '/tmp/',
replicate => false,
activate => true,
force => true,
}
Puppet AEM Curator
• Puppet module for installing and configuring AEM instances
• Written on top of Puppet AEM Resources
• Introduces the concept of AEM Profile
• https://github.com/shinesolutions/puppet-aem-curator
•
Example Usage
aem_curator::install_author { 'Install AEM’:
aem_profile => ‘aem63_sp2_cfp1’,
…
}
Create
Machine Images
Create
AEM Environment
Run
Regression Tests
Deploy
Applications
Fail-fast Build Pipeline
Identify
generic AEM installation
and configuration errors
Identify
environment-specific

AEM configuration errors
Identify
AEM deployment errors
Low probability of
infrastructure errors
Securing AEM
• Set unique admin password for each AEM environment
• Check whether admin/admin login works
• Create system users for replication, deployment,
creating backups
• Disable CRXDE
• Set security-related OSGI configurations
• InSpec profiles
•
AEM OpenCloud
https://www.slideshare.net/cliffano/aem-opencloud
Integration Ideas
AEM OpenAPI spec
Ruby API Client Python API Client
Java API Client JavaScript API Client
Puppet
Chef
InSpec Ansible
Lambda
GulpSpring Boot
SaltStack
Grunt
What’s next?
Specification
• Upgrade to OpenAPI Specification 3.0.1
• OpenAPI Generator 3.0.0 is now available!
More Features
• Create and configure truststore
• Clientlib cache invalidation
• Page activate and deactivate
• Page lock, unlock, and copy
• Bundle install and uninstall
• DAM asset upload
Questions?
Links
• https://github.com/shinesolutions/swagger-aem
• https://github.com/shinesolutions/ruby_aem
• https://github.com/shinesolutions/puppet-aem-resources
• https://github.com/shinesolutions/puppet-aem-curator
Repositories
• https://rubygems.org/gems/swagger_aem
• https://rubygems.org/gems/ruby_aem
• https://pypi.org/project/swaggeraem/
• http://central.maven.org/maven2/com/shinesolutions/swaggeraem4j/
Published libraries
• https://www.slideshare.net/cliffano/aem-opencloud
• https://helpx.adobe.com/experience-manager/kb/common-AEM-Curl-commands.html
• https://github.com/OAI/OpenAPI-Specification
• https://github.com/OpenAPITools/openapi-generator
Resources
Credits
• https://cloudcraft.co/
Diagrams
• https://brorlandi.github.io/StarWarsIntroCreator/
• https://www.flickr.com/photos/28481088@N00/3667291108
• https://wallpapers.walldevil.com/wallpapers/a25/preview/4242-wallpaper-simpsons.jpg
• https://imgflip.com/memetemplate/131319015/Despicable-Me-Diabolical-Plan-Gru-Template
• http://designbusinesscouncil.com/2016/06/29/hear-no-evil/
• https://orig00.deviantart.net/9338/f/2009/351/f/5/picard_on_bridge_by_jjohnson1701.jpg
Images

Beyond AEM Curl Commands

  • 1.
    
 BEYOND AEM CURLCOMMANDS Cliffano Subagio (@cliffano) - Shine Solutions - Adobe Immerse’18

  • 2.
    SHINE SOLUTIONS https://shinesolutions.com AEMCommunity Solution Partner AEM applications and cloud infrastructure projects since 2013 CLIFFANO SUBAGIO cliff.subagio@shinesolutions.com Senior Consultant Creator of AEM OpenCloud
  • 3.
    AGENDA 1. Introduction +history 2. The problems with curl commands 3. API clients as the solution 4. Current and future use cases 5. What’s next?
  • 4.
  • 5.
  • 6.
    This looks harmless… curl -u admin:admin -F package=@“my-aem-package.zip” http://localhost:4502/crx/packmgr/service/.json/?cmd=upload
  • 7.
    But this looksharmful… set -o errexit result=$(curl … ) if [[ $result = *”error” ]]; then exit 123 fi Fragile error checking Uninformative error result Unreliable exit code No success result
  • 8.
    Create Machine Images Create AEM Environment Run RegressionTests Deploy Applications Build Pipeline ~5mins~40mins ~20mins ~30mins Only allows less than 6 pipeline runs per day! curl commands used here cURL command error identified at the end
  • 9.
    Everyone felt unproductive ProjectManager Operations Developers Testers Security Everyone felt unproductive
  • 10.
  • 11.
    Problem 1: cURL commandseverywhere For everything
  • 12.
  • 13.
    JSON Example -Get install status { “status": { “finished": true, “itemCount": 0 } }
  • 14.
    XML Example -Listing packages <crx version="1.4.1" user="admin" workspace="crx.default"> <request> <param name="cmd" value="ls"/> </request> <response> <data> <packages> <package> <group>Adobe/granite</group> <name>com.adobe.granite.httpcache.content</name> <version>1.0.2</version> <downloadName>com.adobe.granite.httpcache.content-1.0.2.zip</downloadName> <size>13323</size> <created>Tue, 25 Feb 2014 10:40:56 +0000</created> <createdBy>Adobe</createdBy> <lastModified></lastModified> <lastModifiedBy>null</lastModifiedBy> <lastUnpacked>Tue, 5 Jun 2018 01:15:49 +0000</lastUnpacked> <lastUnpackedBy>admin</lastUnpackedBy> </package> …
  • 15.
    HTML Example -Creating a user <html> <head> <title>Content created /home/users/s/nWkLPRxMJe5WwsySVrnv</title> </head> <body> <h1>Content created /home/users/s/nWkLPRxMJe5WwsySVrnv</h1> <table> <tbody> <tr> <td>Status</td> <td><div id="Status">201</div></td> </tr> <tr> <td>Message</td> <td><div id="Message">Created</div></td> </tr> … <tr> <td>Path</td> <td><div id="Path">/home/users/s/nWkLPRxMJe5WwsySVrnv</div></td> </tr> …
  • 16.
  • 17.
    (intermittent) Error 401 onpackage upload success { “success”:true, "msg":"Package uploaded”, “path”:”/etc/packages/path/my-package-1.0.zip" }
  • 18.
    Success 200 on changeuser password error • http 200 with empty response body
 when authentication is invalid • http 200 with error message in html response body
 when old password is incorrect
  • 19.
    Problem 4: What ifthere’s no shell? Think serverless!
  • 20.
    Problem 5: Lack ofintegration with various technology stacks
  • 21.
  • 22.
    Swagger AEM • APIspecification for AEM endpoints • Swagger/OpenAPI version 2 • Swagger CodeGenerator -> OpenAPI Generator • Ruby, Python, Java, and JavaScript API clients • https://github.com/shinesolutions/swagger-aem/ •
  • 23.
    OpenAPI Specification /crx/packmgr/service/.json/{path}: post: operationId: postPackageServiceJson produces: -application/json parameters: - name: path in: path required: true type: string - name: cmd in: query required: true type: string - name: groupName in: query required: false type: string - name: packageName in: query required: false type: string - name: packageVersion in: query required: false type: string - name: _charset_ in: query required: false type: string - name: force in: query required: false type: boolean - name: recursive in: query required: false type: boolean - name: package in: formData required: false type: file consumes: - multipart/form-data responses: default: description: 'Default response' schema: type: string tags: - crx
  • 24.
    Ruby AEM • Resourceoriented design • Further abstraction away from AEM endpoints • Error and response objects • Additional custom APIs • https://github.com/shinesolutions/ruby_aem •
  • 25.
    Result Handling package =aem.package('somepackagegroup', 'somepackage', '1.2.3') opts = { force: true } result = package.upload('/tmp', opts) puts result.message puts result.response.status_code puts result.response.body puts result.response.headers puts result.data
  • 26.
    Error Handling begin rescue RubyAem::Error=> err end package = aem.package('somepackagegroup', 'somepackage', '1.2.3') opts = { force: true } result = package.upload('/tmp', opts) puts err.message puts err.result.response.status_code puts err.result.response.body puts err.result.response.headers puts err.result.data
  • 27.
    Problems Solved No dependencyto shell, cloud functions ready Response objects, JSON/XML/HTML included Better status handling, http status code included Easier to integrate with various technologies First class language, not just cURL commands
  • 28.
    Features • Wait untillogin page is ready • Wait until AEM health check is passed • Bundle start, stop • Configuration property create • Replication, reverse replication, and flush agents create, update, delete • User and group create and delete • Add user and group to a group • Node create and delete • Package create, update, delete, upload, install, uninstall, replicate, list, versions • Path activate • Repository block, unblock
  • 29.
  • 30.
    Puppet AEM Resources •Puppet module for provisioning AEM resources • Written on top of ruby_aem • Puppet debug mode support • https://github.com/shinesolutions/puppet-aem- resources •
  • 31.
    Example Usage aem_package {'Install AEM6.2 hotfix 12785': ensure => present, name => 'cq-6.2.0-hotfix-12785', group => 'adobe/cq620/hotfix', version => '7.0', path => '/tmp/', replicate => false, activate => true, force => true, }
  • 32.
    Puppet AEM Curator •Puppet module for installing and configuring AEM instances • Written on top of Puppet AEM Resources • Introduces the concept of AEM Profile • https://github.com/shinesolutions/puppet-aem-curator •
  • 33.
    Example Usage aem_curator::install_author {'Install AEM’: aem_profile => ‘aem63_sp2_cfp1’, … }
  • 34.
    Create Machine Images Create AEM Environment Run RegressionTests Deploy Applications Fail-fast Build Pipeline Identify generic AEM installation and configuration errors Identify environment-specific
 AEM configuration errors Identify AEM deployment errors Low probability of infrastructure errors
  • 35.
    Securing AEM • Setunique admin password for each AEM environment • Check whether admin/admin login works • Create system users for replication, deployment, creating backups • Disable CRXDE • Set security-related OSGI configurations • InSpec profiles •
  • 36.
  • 37.
    Integration Ideas AEM OpenAPIspec Ruby API Client Python API Client Java API Client JavaScript API Client Puppet Chef InSpec Ansible Lambda GulpSpring Boot SaltStack Grunt
  • 38.
  • 39.
    Specification • Upgrade toOpenAPI Specification 3.0.1 • OpenAPI Generator 3.0.0 is now available! More Features • Create and configure truststore • Clientlib cache invalidation • Page activate and deactivate • Page lock, unlock, and copy • Bundle install and uninstall • DAM asset upload
  • 40.
  • 41.
    Links • https://github.com/shinesolutions/swagger-aem • https://github.com/shinesolutions/ruby_aem •https://github.com/shinesolutions/puppet-aem-resources • https://github.com/shinesolutions/puppet-aem-curator Repositories • https://rubygems.org/gems/swagger_aem • https://rubygems.org/gems/ruby_aem • https://pypi.org/project/swaggeraem/ • http://central.maven.org/maven2/com/shinesolutions/swaggeraem4j/ Published libraries • https://www.slideshare.net/cliffano/aem-opencloud • https://helpx.adobe.com/experience-manager/kb/common-AEM-Curl-commands.html • https://github.com/OAI/OpenAPI-Specification • https://github.com/OpenAPITools/openapi-generator Resources
  • 42.
    Credits • https://cloudcraft.co/ Diagrams • https://brorlandi.github.io/StarWarsIntroCreator/ •https://www.flickr.com/photos/28481088@N00/3667291108 • https://wallpapers.walldevil.com/wallpapers/a25/preview/4242-wallpaper-simpsons.jpg • https://imgflip.com/memetemplate/131319015/Despicable-Me-Diabolical-Plan-Gru-Template • http://designbusinesscouncil.com/2016/06/29/hear-no-evil/ • https://orig00.deviantart.net/9338/f/2009/351/f/5/picard_on_bridge_by_jjohnson1701.jpg Images