Tutorial- Extending the Zend Server UI and WebAPI

advertisement
Extending the Zend Server
UI and WebAPI
Adding your own functionality to Zend Server
Presented by Yonni Mendes with cats, spartans, pirates and Obama!
Before we start, kindly visit avast.yonman.net
and install the listed applications & stuff!
Presented by Yonni Mendes, ZS6 UI Tech Leader
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
Who and What is a Yonni
● A restaurant in Los Angeles, California.
Sadly, closed.
● The UI Technological Leader for Zend Server
● A semi-famous male model
Stuff you need:
Also
IDE
Zend Server
● A father
Ahoy World
● A gamer
Chrome: Dev HTTP
Firefox: Firebug, live
HTTP Headers
● A technologist
Sqlite database manager
Ask me about the extra thing of choice
But first…
Some exercises to
get the blood
flowing
Stand up please!
Stuff you need:
IDE
Zend Server
Ahoy World
Chrome: Dev HTTP
Firefox: Firebug, live
HTTP Headers
Sqlite database manager
of choice
•
•
Topics
Create a basic 3rd party module
Understanding ZS6
o
o
•
o
Under the Zend Server 6 hood
Beasts and common practices of ZS6
Lets make our module do somethingStuff you need:
Some more modules that
are out there
IDE
Zend Server
Ahoy 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
And, for us, most
importantly:
B.W.C
Stuff you need:
IDE
Zend Server
Ahoy World
Chrome: Dev HTTP
Firefox: Firebug, live
HTTP Headers
Sqlite database manager
of choice
The first steps:
3rd party module
So you want to add some functionality...
A few ZF2 buzzwords
These 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
●
We also want to control this toggle from other remote
sources via WebAPI
UI
Andy the admin’s
requirements
• Access to toggle the application state
o Anywhere, Anytime, not on a production port 80
o 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
• Show some general app information too
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 Server
o Linux/mac:
/usr/local/zend/gui/lighttpd/etc/conf.d/optimizerplus.ini
•
o
the UI (Configuration|Components)
Restart Zend Server
o
o
•
Windows: Through
Throught the UI (localhost:10081)
Command line (<install_dir>/bin/zendctl.sh
restart)
Recommended:
open <install_dir>/gui as a php project in the
IDE
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
link to ./vendor
o Add ‘Avast’ to application.config.php
o
•
Open localhost:10081/ZendServer/Avast
Note case sensitive URL
Result: 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
o
•
This is because of a bug in the ACL system
There is no resource called “Avast" and therefore no
controller is found ... ergo 404
ACL requires SQL entries
o
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 of your
module
• 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 and monitor 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 use
2. Show its usage in the ZS6 codebase
3. Integrate it to some extent into your module
Our goal:
1.
Create a functioning, usable module for ZS6
2.
Module will provide functionality in webapi
3.
Module will also provide a UI interface to use the above functionality
4.
Have fun!
Files you might want to
watch
Linux
● gui/lighttpd/logs/zend_server_ui.log
● gui/lighttpd/logs/php.log
Windows
● logs/zend_server_ui.log
● logs/php.log
You can access both through the Zend Server
UI (Overview|Logs)
•
•
•
ZF2: Navigation override
navigation.global.config.php
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
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')
Spotlight:
Deployment\FilteredAccessMapper
● Wraps another mapper, which wrapper yet
another, foreign mapper. Good times.
● Things of interest
○
○
FilteredAccessMapper::getMasterApplicationsByIds
Deployment\Application\Container
Ask me about the big dirty lie!
Foreign code is 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
● Avoid directly referring to foreign code
directly
Ask me why aggregate and not extend!
An aside:
Integration in good practice
Recommended 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
Exercise Avast-03-applications
Add a visual status indicator
Requirement:
● UI will show a toggle status indicator for
Ahoy World
Thoughts on how to integrate with the
AhoyWorld Application?
Meanwhile, in AhoyWorld
<ahoyworld-url>/Status
A 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 visual indicator for the current state.
Retrieve state from AhoyAPI Status
Result: Visual indicator will display correct
Exercise Avast-04-StatusIndicator
application state
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 and monitor 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 header
o
•
o
application/vnd.zend.serverapi+json
Can be X-Accept too (Ask me why!)
Sign the request using
SignatureGenerator
Date should be a GMT with specific format
o Use key obtained in the WebAPI section of UI
o Machines may have to have their clocks synched
o
Good news: We don’t need any of the above
Tools: Request simulation
How’s about we sees us 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 route
Create 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'
'versions'
=> 'avastAhoyStatus',
=> 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.db
INSERT 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’d
Reminder:
● 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
o
•
o
Extends WebAPIActionController class
Add to controllers in module.config
(AvastWebAPI_1-5)
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
format
•
o avast/web-api/1x5/<action>.pjson.phtml
o avast/web-api/1x5/<action>.pxml.phtml
o <action> has dashed inflection: avastahoy-status
o Wrapped by layout.p<output>.phtml automatically
o 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 exercise
Result: 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 should respond
to
Exercise Avast-05-avastAhoyStatus
requests with meaningful information
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
avastAhoyToggle
functionality
● 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 and monitor 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/License
o
•
o
Identity ACL initialized from the database
 GUI_ACL_ROLES, GUI_ACL_RESOURCES,
GUI_ACL_PRIVILEGES
 Roles: administrator, developer,
developerLimited
License ACL initialized within the application
ACL Resources are prefixed:
o
o
route - to indicate this is an MVC controller resource
data - to indicate this is a logical resource
•
•
•
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 ZendServerAcl
ZendServer\..\PhpRenderer - for view usage
o ZendServer\..\ActionController - inherited by every
controller in the ZS6 UI application
o ZendServer\..\DefaultNavigationFactory for
navigation rendering
o and others...
o
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 methods
isAllowed(‘route:<controller>’, ‘<action>’)
ACL: limit access to WebAPI
● avastAhoyStatus should be accessible to
admin and developer alike
● avastAhoyToggle should be accessible to the
admin only
Exercise:
Add an isAclAllowed check in Controller action
If fails, throw a WebAPI\Exception
Exception 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 only
Exercise:
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
Affect button availability according to acl
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 and monitor of Ahoy
●
Provide a UI button to control Ahoy
Extras
Should 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
Practices
Complex and silly things
Logging
•
Zend Server UI log: zend_server_ui.log
o
o
•
•
o
Linux: <zend-server>/gui/lighttpd/logs
Windows: <zend-server>\logs
Written to by class ZendServer\Log\Log
Verbosity change be changed in the Settings
o
Default value is notice and up
Logs can be viewed in the Logs page
Relies on GUI_AVAILABLE_LOGS table
o You can add logs, table is cleared during upgrade
o
Debugging the ZS UI
When 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 Authentication
o
o
Login
Group2
...
App 2
Group3
o
LDAP
List of
Apps
Authenticate user credentials
o Create session Identity object
o Determine allowed applications
o End result: Identity has a list of
allowed applications
App 1
Group1
User
Groups
•
o
Identity Groups
Groups to Apps mapping
CustomAuth module
Zend Server
Session
storage
IdentityFilter - Use and
usage
• Classes implement IdentityFilterInterface
interface IdentityFilterInterface {
public function filterAppIds($applicationIds, $emptyIsAll);
public function setAddGlobalAppId($addGlobalAppId);
}
•
filterAppIds
o
•
o
Intersect identity applications with $applicationIds
If empty applications, check $emptyIsAll
setAddGlobalAppId
o
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 scripts
o Some initial data is rendered by calling a relevant
view script directly
o Using WebAPI from the Zend Server UI client is
easy! (ask me why!)
Nested webapi requests
Should I respond
to this request?
Somewhere
in the
internet...
WebAPI Request
Used by:
• Logs display
• Server info
• Codetracing details view
Zend
Server
Webapi
ZS6
cluster
db
Zend
Server
Webapi
WebAPI validation
Set 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
/usr/local/zend/gui/vendor/ThankYou/src/HadFun/Cya.php
Give me a wonderful review: https://joind.in/9049
Feedback: yonni.m@zend.com, @zendsui,
https://joind.in/9049, linkedin.com/in/yonman
Download