tutorial: extending the zend server ui and web api
DESCRIPTION
This is a Tutorial given at ZendCon 2013 about Zend Server 6's UI extensibilityTRANSCRIPT
Extending the Zend Server UI and WebAPIAdding your own functionality to Zend ServerPresented by Yonni Mendes with cats, spartans, pirates and
Obama!
Presented by Yonni Mendes, ZS6 UI Tech Leader
Before we start, kindly visit avast.yonman.net and install the listed
applications & stuff!
Setup: what you should have● Zend Studio, or other IDE of choice● Zend Server● AhoyWorld zpk deployable● Tutorial package
○ Skeletons○ Exercise snippets○ Complete code
● Recommended○ Chrome: Dev HTTP Client or similar○ Firefox: Firebug, live HTTP Headers or
similar○ Sqlite database manager of choice
Who and What is a Yonni● A restaurant in Los Angeles,
California.Sadly, closed.
● A semi-famous male model● The UI Technological Leader for Zend
ServerAlso● A father● A gamer ● A technologistAsk me about the extra thingyou should know!
Stuff you need:
IDEZend ServerAhoy World
Chrome: Dev HTTP Firefox: Firebug, live HTTP Headers
Sqlite database manager of choice
But first…
Some exercises to get the bloodflowing
Stand up please!
Stuff you need:
IDEZend ServerAhoy World
Chrome: Dev HTTP Firefox: Firebug, live HTTP Headers
Sqlite database manager of choice
Topics• Create a basic 3rd party module
• Understanding ZS6o Under the Zend Server 6 hoodo Beasts and common practices of ZS6o Lets make our module do something
• Some more modules thatare out there
Stuff you need:
IDEZend ServerAhoy World
Chrome: Dev HTTP Firefox: Firebug, live HTTP Headers
Sqlite database manager of choice
Why extend ZS6?● Zend Server’s unique position● Zend Server’s existing platform &
services
Stuff you need:
IDEZend ServerAhoy World
Chrome: Dev HTTP Firefox: Firebug, live HTTP Headers
Sqlite database manager of choice
And, for us, most importantly:
B.W.C
The first steps:3rd party module
So you want to add some functionality...
A few ZF2 buzzwordsThese are a few devices we will need● ServiceManager, Factories● Merged config arrays● Modules, Module manager
Our scenario● We have an application, “Ahoy World!”
○ Deploy it (https://github.com/YonmaN/AhoyWorld)
● This application can be turned on and off
● We want to allow a user logged into Zend Server to control this toggle directly from the UI
● We also want to control this toggle from other remote sources via WebAPI
Andy the admin’s req’s•Show some general app information•Access to toggle the application state
o Anywhere, Anytime, but not direct accesso No access to those Creative Type People over
at marketing
•Human UI and API access•Must be secure
o But: Do not create a new user authentication system, nor modify the existing one at Ahoy
•In fact, do not modify AhoyWorld at all
Our Module: Avast● WebAPI will allow a client to:
○ Retrieve the current status of the site (on or off)
○ Toggle the current status of the site○ Rely on external code that’s included into the
module
● UI will display the deployment information about our application
● UI will only show a status indicator to the developer, nothing else
● UI will show a toggle button that allows the admin to turn the site on or off
Functional requirements● ZF2 module, use ZF2 features, be ZF2
compliant● WebAPI will return both json and xml
output● UI page will be integrated in the ZS6
ACL● UI page will show up in the navigation
page● UI will be accessible only to a logged
in user
Preparing to develop for ZS6• Switch off opcode cache in Zend
Servero Linux/mac:
/usr/local/zend/gui/lighttpd/etc/conf.d/optimizerplus.ini
o Windows: Through the UI (Configuration|Components)
• Restart Zend Servero Throught the UI (localhost:10081)o Command line (<install_dir>/bin/zendctl.sh
restart)
• Recommended:open <install_dir>/gui as a php project in the IDE
• Find the gui/vendor directory
Warning! Confusion ahead!● Zend Studio copies files● Changes may not apply● You may have to make some changes
manually● Particularly, the vendor library
changes
Creating a new module, the hard way● Create a new php project● zendframework/ZendSkeletonModule● Unzip into your workspace folder● Rename everything that needs
renaming
Rename gotta rename● Folder names
○ in src
● File names○ Controller filename○ view scripts
● Controller class name
Create a new module, the easy way● Create a new php project● Unzip avast.yonman.net/Avast-00-Initial.zip
Important: can you create a symbolic link?
Recommended: add the Zend GUI project as a library to the new module project, in ‘include path’
Make a connection● In the Zend Server UI directory
o link to ./vendoro Add ‘Avast’ to application.config.php
• Open localhost:10081/ZendServer/Avast
Note case sensitive URLResult: error :(
Necessary changes● Remove the entire router entry● Replace controllers entry
'invokables' => array(
'Avast' => 'Avast\Controller\AvastController',
),
Result: Still error!
ACL entries and overrides• Pitfall: GUI will now return 404!
o Bug in the ACL systemo Missing resource called "skeleton"...o Therefore no controller is found ... ergo 404
• Fix: ACL requires SQL entrieso sqlite: var/db/gui.db or data/db/gui.db
INSERT OR IGNORE INTO GUI_ACL_RESOURCES VALUES(NULL,'route:Avast');
INSERT OR IGNORE INTO GUI_ACL_PRIVILEGES VALUES(3, last_insert_rowid(), '');
(Place in sqls in a dedicated sql file - acl.sqlite.entries.sql)
Result: localhost:10081/ZendServer/Avast should respond correctly Exercise Avast-01-acl
Installation process summary• Unpack / link module into ./vendor
• Add module name to application.config.php
• Run SQLs
• Copy any config.php files into ./config/autoload
• Copy any public directory assets to the public direcotry (js, images, css)
Bask in the glory of your Module!
Our module can now:● Display an empty page● Override navigation bar● Display app info & status indicator● Provide WebAPI control of Ahoy● Provide a UI button to control Ahoy
Avast ye landlubbers!Lets make things interesting
Lets grease those elbows!From here on:1.Describe a tool or ZS6 subsystem and
its use2.Show its usage in the ZS6 codebase3. Integrate it to some extent into your
moduleOur goal:1.Create a functioning, usable module
for ZS62.Module will provide functionality in
webapi3.Module will also provide a UI interface
to use the above functionality4.Have fun!
Files you might want to watchLinux● gui/lighttpd/logs/zend_server_ui.log● gui/lighttpd/logs/php.logWindows● logs/zend_server_ui.log● logs/php.logYou can access both through the Zend
Server UI (Overview|Logs)
ZF2: Navigation override• navigation.global.config.ph
p
• We wish to add a new Avast tab
• Tab should use Avast controller
Exercise: Override the navigation array in Avast/module.config.php
Ask me about ZS6.2!
Result: Navigation bar should show Avast tabs that can be used
Exercise Avast-02-navigation
Calling the ZS databases• You’ll want to do this through our
mappers
• If you want to build a new mapper ...o ServiceManager and delegated Di
DbConnector::factory Driver Connection Adapter TableGateway Mapper
o Can also call ServiceManager->get('PDO')
Ask me about ZS6.2!
Spotlight: Deployment\FilteredAccessMapper
● Wraps another mapper, which wrapper yet another, foreign mapper. Good times.
● Things of interest○ FilteredAccessMapper::getMasterApplication
sByIds○ Deployment\Application\Container
Ask me about the big dirty lie!
An aside:Foreign code, a cruel mistress● Next we will implement
○ Avast UI has to show deployment information about “Ahoy World”
○ Use Deployment\FilteredAccessMapper class to retrieve and display data
● Use foreign code carefully to avoid errors
● Aggregate, don’t inherit (Ask me why )
● Avoid referring to foreign code directly
Lets integrateRecommended approach:● Create an aggregating class for
FilteredAccessMapper● Implement findAhoyApplication() code in
class● Integrate your class into the controller
Can go the extra mile - wrap the application container that is returned
Calling the database● Avast UI has to show deployment
information about “Ahoy World”● Use Deployment\FilteredAccessMapper
class to retrieve and display data
Exercise: Integrate a call to retrieve all applications. Find ‘Ahoy World’ application data.
Show this data in your view script.Ask me why there’s no native
“getApplicationByName” method!Exercise Avast-03-applications
Add a visual status indicatorRequirement:● UI will show a toggle status indicator
for Ahoy World
Thoughts on how to integrate with the AhoyWorld Application?
Meanwhile, in AhoyWorld<ahoyworld-url>/StatusA restfull api returns the current
application status
JSON output:{"status":true}
Add a visual status indicator...Requirement:● UI will show a toggle status indicator
for Ahoy World
Exercise:Add a static visual indicator for the
current state.Retrieve result without duplicating
functionalityResult: Visual indicator will display
correct infoExercise Avast-04-StatusIndicator
Bask in the glory of your Module!
Our module can now:● Display an empty page● Override navigation bar● Display app info & status indicator● Provide WebAPI control of Ahoy● Provide a UI button to control Ahoy
WebAPI ho!It’s not Zend Server if there’s no WebAPI
WebAPI: How does one use it• Create a request using Zend\Http\Client
• Add an Accept headero application/vnd.zend.serverapi+jsono Can be X-Accept too (Ask me why!)
• Sign the request using SignatureGeneratoro Date should be a GMT with specific formato Use key obtained in the WebAPI section of UIo Machines may have to have their clocks
synched
Good news: We don’t need any of the above
Ask me Why!
Tools: Request simulationHow about we see an example?● URL: localhost:10081/ZendServer/Api/getSystemInfo● Header: Accept: ….
○ To version or not to version?■ application/vnd.zend.serverapi+json;version=1.5
○ Output type?
● Get or post?● Signed request or session hijacking?● Inspecting the response
WebAPI: avastAhoyStatus● WebAPI action to return the current
state of Ahoy’s master directive● No parameters● Output: json and xml
We want to create the avastAhoyStatus route & ACL
…but how do we do that?
Create a WebAPI routeCreate a Literal route in module.config.php'webapi_routes' => array(
'AvastWebAPI' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/Api/example',
'defaults' => array(
'controller' => 'AvastWebAPI',
'action' => 'avastAhoyStatus',
'versions' => array('1.5'),
),
))
)
...
Ask me about more route options!Tell me: what did I forget?
More ACL entries and overrides• ACL requires SQL entries
o sqlite, db/gui.dbINSERT OR IGNORE INTO GUI_ACL_RESOURCES VALUES(NULL,'route:AvastWebAPI');
INSERT OR IGNORE INTO GUI_ACL_PRIVILEGES VALUES(3, last_insert_rowid(), '');
• These queries have to be reapplied after upgrades
• Controller names are case sensitive
Ask me about exceptions!
avastAhoyStatus, cont’dReminder:● WebAPI action to return the current
state of Ahoy’s master directive● No parameters● Output: json and xml
We want to create a controller and view scripts
…but how do we do that?
Lets add a WebAPI controller• Class WebAPIController
o Extends WebAPIActionController classo Add to controllers in module.config
(AvastWebAPI_1-5)o Controller names are case sensitive
• Action should be named as indicated by the route’s action parameter
Lets add a WebAPI view script• Actions need View scripts - one for
each formato avast/web-api/1x5/<action>.pjson.phtmlo avast/web-api/1x5/<action>.pxml.phtmlo <action> has dashed inflection: avast-
ahoy-statuso Wrapped by layout.p<output>.phtml
automaticallyo Create a string that “nestles” within the
layout
• View script has to include “responseData” wrapper element in json and xml
avastAhoyStatus, cont’d● WebAPI action to return the current
state of Ahoy’s master directive● No parameters● Output: json and xml
Exercise: Create the avastAhoyStatus webapi controller & action
Exercise: Create json and xml view scripts
Use dummy data for this exerciseResult: avastAhoyStatus responds to
requests
avastAhoyStatus functionality● Add functionality to our webapi action● Retrieve a boolean status● Pass it out to the view script
Exercise: Use Integration Stub to retrieve status
Replace the dummy data from the previous exercise
Result: avastAhoyStatus responds correctly
Exercise Avast-05-avastAhoyStatus
WebAPI: avastAhoyToggle● WebAPI action to return the updated
state of Ahoy’s master directive● Parameter: state● Output: json and xml
Exercise: Create the avastAhoyToggle route
Exercise: Create the avastAhoyToggle webapi
Exercise: Create json and xml output, similar or identical to avastAhoyStatus
Result: avastAhoyToggle responds to requests
WebAPI: avastAhoyToggle ● Add functionality to our webapi action● Collect a parameter and validate it● Pass the parameter to a toggle method
Exercise: Use <ahoyworld-url>/Status/Toggle to change AhoyWorld’s status
Result: calls to avastAhoyToggle affect AhoyWorld
Exercise Avast-06-avastAhoyToggle
Bask in the glory of your Module!
Our module can now:● Display an empty page● Override navigation bar● Display app info & status indicator● Provide WebAPI control of Ahoy● Provide a UI button to control Ahoy
Lets make our UI do a jig
Shiver me timbers!
Javascript!● WebAPI is everywhere in the UI● Different usage scenarios● Some tools we provide
○ zswebapi.js○ zgridPolling.js○ FragmentManager.js
Ask me about the exceptions to the rule!
Integrate WebAPI into the UI● Status indicator● Button that will call our toggle webapi● Use toggle response to update
indicator
Exercise: use Request.WebAPI to call the toggle
Result: We have a button that lets the user affect AhoyWorld directly
Exercise Avast-07-webapiButton
Requirements reminder● avastAhoyStatus should be accessible
to admin and developer alike● avastAhoyToggle should be accessible
to the admin only
ACL in Zend Server• ACL is consulted for every request
• Two ACLs: Role/Identity, Edition/Licenseo Identity ACL initialized from the database
GUI_ACL_ROLES, GUI_ACL_RESOURCES, GUI_ACL_PRIVILEGES
Roles: administrator, developer, developerLimited
o License ACL initialized within the application
ACL in Zend Server• ACL Resources are prefixed:
o route - to indicate this is an MVC controller resource
o data - to indicate this is a logical resourceo service - to indicate this is a system-wide
resource
• Privileges may allow particular actions
ACL in Zend Server, cont'd• AclQuery class, registered services
o ZendServerAcl (AclQuery class)o ZendServerEditionAcl (Acl class)o ZendServerIdentityAcl (Acl class)
• AclQuery is used many places
• AclQuerierInterface sets ZendServerAclo ZendServer\..\PhpRenderer - for view usageo ZendServer\..\ActionController - inherited by
every controller in the ZS6 UI applicationo ZendServer\..\DefaultNavigationFactory for
navigation renderingo and others...
ACL: limit access to WebAPI● avastAhoyStatus should be accessible
to admin and developer alike● avastAhoyToggle should be accessible
to the admin onlyExercise: Modify your module’s SQLs to
map these ACL directives. Apply the new directives immediately to your gui.db and acl.sqlite...sql
Result: Developer user gets an error for toggle
Ask me about the neat trick!
Exercise Avast-08-webapiAclLimit
ACL: querying in MVC● Acl Queries can be performed in view
script○ PhpRenderer::isAllowed()○ PhpRenderer::isAllowedIdentity()○ PhpRenderer::isAllowedEdition()
● Acl Queries can also be used in controllers○ ActionController::isAclAllowed()○ ActionController::isAclAllowedIdentity(
)○ ActionController::isAclAllowedEdition()
Parameters for isAllowed*For all of the previous methodsisAllowed(‘route:<controller>’,
‘<action>’)
ACL: limit access to WebAPI● avastAhoyStatus should be accessible
to admin and developer alike● avastAhoyToggle should be accessible
to the admin onlyExercise:Add an isAclAllowed check in Controller
actionIf fails, throw a WebAPI\ExceptionException Code: INSUFFICIENT…Result: action doesn’t fail… what did we
forget?
ACL: limit access, cont’d● avastAhoyStatus ... admin and
developer● avastAhoyToggle should be accessible
to the admin onlyExercise:Modify SQLs to map ACL directives.
Apply the new directives immediately to your gui.db
Result: Developer user gets an error for toggle
Ask me about the neat trick!
Exercise Avast-08-webapiAclLimit
ACL: affecting presentation● Ahoy status indicator should be visible
to anyone● Ahoy toggle button should be available
only to an administrator
Exercise: Add ACL queries to the view script
Result: Ahoy toggle button does not get displayed at all to the developer
Exercise Avast-09-uiAclLimits
Bask in the glory of your Module!
Our module can now:● Display an empty page● Override navigation bar● Display app info & status indicator● Provide WebAPI control of Ahoy● Provide a UI button to control Ahoy
ExtrasShould we have the time & spirit...
Add polling to the Avast page● zgridPolling, Request.WebAPI
○ Poll avastAhoyStatus○ Polling populates button label and indicator
label
● Polling removes the need to refresh the page after toggle button is pressed
Calling the database: extended● Clusters require we show the
application status for every server, not just its aggregate.
● Show each server’s state for AhoyWorld
● Servers\Db\Mapper methods will assist
Exercise: Use the application’s servers list to cross reference with the available servers list
Create an avastAppInfo WebAPI● Move the functionality of retrieving
application data form the UI into a webapi action
● This can be used for page display by polling avastAppInfo from the page
PracticesComplex and silly things
Logging• Zend Server UI log: zend_server_ui.logo Linux: <zend-server>/gui/lighttpd/logso Windows: <zend-server>\logso Written to by class ZendServer\Log\Log
• Verbosity change be changed in the Settingso Default value is notice and up
• Logs can be viewed in the Logs pageo Relies on GUI_AVAILABLE_LOGS tableo You can add logs, table is cleared during
upgrade
Debugging the ZS UIWhen debugging your module inside
ZS6:● Log verbosity should stay on notice
○ Throw out messages in high levels like “alert”○ Debug level throws out LOTS of information
● UI is constantly polling, you may face lots of log entries that are unrelated to your own code○ zend_gui.debugModeEnabled = true adds the
request URI to the log entry○ Allows you to filter the entries
...
IdentityFilter - Authentication• Simple Authentication
• Extended Authenticationo Identity Groupso Groups to Apps mappingo CustomAuth module
• Logino Authenticate user credentialso Create session Identity objecto Determine allowed applicationso End result: Identity has a list of
allowed applicationsU
ser
Gro
ups
List of
App
s
Group1
Group2
Group3
App 1
App 2
Zend Server
LDAPSession storage
IdentityFilter - Use and usage• Classes implement
IdentityFilterInterfaceinterface IdentityFilterInterface {
public function filterAppIds($applicationIds, $emptyIsAll);
public function setAddGlobalAppId($addGlobalAppId);
}
• filterAppIdso Intersect identity applications with
$applicationIdso If empty applications, check $emptyIsAll
• setAddGlobalAppIdo Global application (Ask me what that is!)
UI compounded services• Compound services
o Controllers call other controllers using forward->dispatch plugin
o MVC Failures are handled by dispatch.error event and event handlers
o Nested WebAPI calls in clusters (An example?)
• View scriptso Some initial data is rendered by calling a
relevant view script directlyo Using WebAPI from the Zend Server UI client
is easy! (ask me why!)
Nested webapi requests
Somewhere in the internet...
WebAPI RequestZend
Server Webapi
Should I respond to this request?
Zend Server Webapi
ZS6 cluster
db
Do I have any friends?
Used by:• Logs display• Server info• Codetracing details view
WebAPI validationSet of validation functions that throw
exceptions
• Integrated into all existing webapi actions
• ZendServer\Mvc\Controller\WebAPIActionController
• ZendServer\Mvc\Controller\ActionController
Existing ZS6 Modules● Populated with code written by Zend
developers● No warranty and no SLA cover● Highlights
○ ZendServer-TokenAuthentication○ ZendServer-CustomAuth○ ZendServerNagiosPlugin
● External and peripheral integration○ ZendServerWebApiModule○ ZendServerSDK○ ZendServerDeploymentHelper
Feedback: [email protected], @zendsui, https://joind.in/9049, linkedin.com/in/yonman
/usr/local/zend/gui/vendor/ThankYou/src/HadFun/Cya.php
Give me a wonderful review: https://joind.in/9049