Webviews

0

Wavemaker and vCO – The next level

Remember these?

http://www.vcoportal.de/2011/11/using-wavemaker-as-web-frontend-for-vco/
http://www.virtuallyghetto.com/2011/12/leveraging-vcd-vco-wavemaker-part-1.html
http://www.virtuallyghetto.com/2011/12/leveraging-vcd-vco-wavemaker-part-2.html
http://mighty-virtualization.blogspot.de/2011/11/vco-wavemaker-your-cloud-webservice.html
https://www.youtube.com/watch?v=zSn7WhX5Wc0 

This week VMware released a new Fling: “Wavemaker Integration with vCenter Orchestrator”

https://labs.vmware.com/flings/wavemaker-integration-for-vcenter-orchestrator

This fling allows you to:

  • Run the included WaveOperator demo project, that provides common tasks (like start and monitor workflow execution), comparable to the weboperator webview in vCO
  • Use the widgets to create your own web interface for your workflows
  • Use the Java Services that expose the vCO API into Wavemaker projects

Sounds cool? Is cool! No more manual getting things together, but predefined wavemaker widgets for your workflows to just drag and drop into yourweb interface!

But wait, there’s more! The project is available open source on Github: https://github.com/vmware/wavemaker_integration

So you can even expand the functionality to your needs, or adopt the code for your projects.

3

Howto setup LDAP-Authentication for Wavemaker (Part 2)

Remember Part 1:

http://www.vcoportal.de/2012/05/howto-setup-ldap-authentication-for-wavemaker-part-1/

The Workaround

In the solution of Part 1, you can only find groups in one OU. In the wavemaker community, there are some links to additional documentation, were this post is based on.

Let’s have a look to the AD. In the Wavemaker examples a “flat” AD Structure is used

Whow, I have never seen an AD like this….. In the Wavemaker community examples always a “flat” AD environment is used. In such an environment it is easy to setup a Group Authentication…but in the environments, where I work I never had such an easy AD. So let’s have a look to a “real” AD:

When you use Wavemaker to configure your AD you are limited in the GUI. You cannot point your configuration to different OUs. Your only option is to get user out of one OU. But how do you configure your application if your users were sprawl in different OUs?

So when your people are from different OUs you have a problem….
For this problem, there is a solution, but therefore you have to make your LDAP configuration manually. First of all, you have to configure your AD Server connection. I assume that you have done this already. After that, we need some configuration changes…

First we have do modify the file project-security.xml. This is located under:

%PROJECTPATH%\webapproot\WEB-INF\project-security.xml

Insert the following code

<bean id="userSearch">

<constructor-arg index="0">

<value>cn=users</value> --> Here you must put the parent directory were to start the user search

</constructor-arg>

<constructor-arg index="1">

<value>(sAMAccountName={0})</value>

</constructor-arg>

<constructor-arg index="2">

<ref local="initialDirContextFactory"/>

</constructor-arg>

<property name="searchSubtree">

<value>true</value>

</property>

</bean>

One word to the code above, I was not able to start my search onto the root of the domain. I didn’t find a solution to start the search from there! I had to choose a OU or subfolder.

After that, you have to change some code in the file… See the screenshot for the “summary” of all changes, and find the complete before/after .xml-files below.

Be aware: After that, you cannot use the  LDAP configuration page in Wavemaker anymore! If you do so, everything will be overwritten and you have to start from scratch again!

The limitation above is not a Wavemaker limitation but comes from the used ACEGI Security which is used in Wavemaker. Additional information can be found here:

http://www.opennms.org/wiki/Acegi_Security_and_LDAP

So have fun with Orchestrator, Wavemaker and your Active Directory!

Complete before/after-xml-files

Change this…

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<beans xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <bean id="filterChainProxy">
 <property name="filterInvocationDefinitionSource">
 <value>
 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
 PATTERN_TYPE_APACHE_ANT
 /**=httpSessionContextIntegrationFilter,logoutFilter,formAuthenticationProcessingFilter,anonymousProcessingFilter,jsonExceptionTranslationFilter,filterSecurityInterceptor
 </value>
 </property>
 </bean>
 <bean id="httpSessionContextIntegrationFilter"/>
 <bean id="logoutFilter">
 <constructor-arg value="/index.html"/>
 <constructor-arg>
 <list>
 <bean/>
 </list>
 </constructor-arg>
 <property value="/j_acegi_logout" name="filterProcessesUrl"/>
 </bean>
 <bean id="formAuthenticationProcessingFilter">
 <property name="filterProcessesUrl">
 <value>/j_acegi_security_check</value>
 </property>
 <property name="authenticationFailureUrl">
 <value>/login.html?login_error=1</value>
 </property>
 <property name="defaultTargetUrl">
 <value>/</value>
 </property>
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 </bean>
 <bean id="jsonExceptionTranslationFilter">
 <property name="authenticationEntryPoint">
 <ref bean="formLoginAuthenticationEntryPoint"/>
 </property>
 </bean>
 <bean id="formLoginAuthenticationEntryPoint">
 <property name="loginFormUrl">
 <value>/login.html</value>
 </property>
 <property name="forceHttps">
 <value>false</value>
 </property>
 </bean>
 <bean id="anonymousProcessingFilter">
 <property name="key">
 <value>sharedsecret</value>
 </property>
 <property name="userAttribute">
 <value>anonymousUser,ROLE_ANONYMOUS</value>
 </property>
 </bean>
 <bean id="anonymousAuthenticationProvider">
 <property name="key">
 <value>sharedsecret</value>
 </property>
 </bean>
 <bean id="filterSecurityInterceptor">
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 <property name="accessDecisionManager">
 <ref bean="accessDecisionManager"/>
 </property>
 <property name="objectDefinitionSource">
 <value>
 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
 PATTERN_TYPE_APACHE_ANT
 /*.upload=IS_AUTHENTICATED_FULLY
 /*.download=IS_AUTHENTICATED_FULLY
 /index.html=IS_AUTHENTICATED_FULLY
 /=IS_AUTHENTICATED_FULLY
 /securityservice.json=IS_AUTHENTICATED_ANONYMOUSLY
 /*.json=IS_AUTHENTICATED_FULLY
 </value>
 </property>
 </bean>
 <bean id="authenticationManager">
 <property name="providers">
 <list>
 <ref bean="ldapAuthProvider"/>
 <ref bean="anonymousAuthenticationProvider"/>
 </list>
 </property>
 </bean>
 <bean id="daoAuthenticationProvider">
 <property name="userDetailsService">
 <ref bean="inMemoryDaoImpl"/>
 </property>
 </bean>
 <bean id="inMemoryDaoImpl">
 <property name="userMap">
 <value>
 demo=demo,ROLE_DEFAULT_NO_ROLES
 </value>
 </property>
 </bean>
 <bean id="jdbcDaoImpl">
 <property name="dataSource">
 <ref bean="jdbcDataSource"/>
 </property>
 <property name="usersByUsernameQuery">
 <value>SELECT first_name, last_name, 1 FROM employee WHERE first_name = ?</value>
 </property>
 <property name="authoritiesByUsernameQuery">
 <value>SELECT first_name, "DEFAULT_NO_ROLES" FROM employee WHERE first_name = ?</value>
 </property>
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 <property name="usernameBasedPrimaryKey">
 <value>true</value>
 </property>
 </bean>
 <bean id="jdbcDataSource"/>
 <bean id="ldapAuthProvider">
 <constructor-arg>
 <bean>
 <constructor-arg>
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <property name="userDnPatterns">
 <list>
 <value>cn={0},ou=people</value>
 </list>
 </property>
 </bean>
 </constructor-arg>
 <constructor-arg>
 <bean>
 <constructor-arg>
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <constructor-arg>
 <value>ou=groups</value>
 </constructor-arg>
 <property name="groupSearchDisabled">
 <value>false</value>
 </property>
 <property name="roleProvider">
 <value>LDAP</value>
 </property>
 <property name="groupRoleAttribute">
 <value>cn</value>
 </property>
 <property name="groupSearchFilter">
 <value>(member={0})</value>
 </property>
 </bean>
 </constructor-arg>
 </bean>
 <bean id="initialDirContextFactory">
 <constructor-arg value="ldap://localhost:389/dc=wavemaker,dc=com"/>
 <property name="managerDn">
 <value>cn=manager,dc=wavemaker,dc=com</value>
 </property>
 <property name="managerPassword">
 <value>7b6a43524a282c146a6b626e425c32205754</value>
 </property>
 </bean>
 <bean id="accessDecisionManager">
 <property name="allowIfAllAbstainDecisions">
 <value>false</value>
 </property>
 <property name="decisionVoters">
 <list>
 <bean/>
 <bean/>
 </list>
 </property>
 </bean>
 <bean id="roleVoter">
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 </bean>
 <bean id="autoProxyCreator">
 <property name="proxyTargetClass">
 <value>true</value>
 </property>
 <property name="interceptorNames">
 <list>
 <value>securityInterceptor</value>
 </list>
 </property>
 </bean>
 <bean id="securityInterceptor">
 <property ref="authenticationManager" name="authenticationManager"/>
 <property ref="accessDecisionManager" name="accessDecisionManager"/>
 <property name="objectDefinitionSource">
 <value>
 </value>
 </property>
 </bean>
 <bean scope="singleton" id="securityService">
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 <property name="noRolesMarkerRole">
 <value>DEFAULT_NO_ROLES</value>
 </property>
 <property name="roles">
 <list/>
 </property>
 </bean>
</beans>

…to this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<beans xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <bean id="filterChainProxy">
 <property name="filterInvocationDefinitionSource">
 <value>
 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
 PATTERN_TYPE_APACHE_ANT
 /**=httpSessionContextIntegrationFilter,logoutFilter,formAuthenticationProcessingFilter,anonymousProcessingFilter,jsonExceptionTranslationFilter,filterSecurityInterceptor
 </value>
 </property>
 </bean>
 <bean id="httpSessionContextIntegrationFilter"/>
 <bean id="logoutFilter">
 <constructor-arg value="/index.html"/>
 <constructor-arg>
 <list>
 <bean/>
 </list>
 </constructor-arg>
 <property value="/j_acegi_logout" name="filterProcessesUrl"/>
 </bean>
 <bean id="formAuthenticationProcessingFilter">
 <property name="filterProcessesUrl">
 <value>/j_acegi_security_check</value>
 </property>
 <property name="authenticationFailureUrl">
 <value>/login.html?login_error=1</value>
 </property>
 <property name="defaultTargetUrl">
 <value>/</value>
 </property>
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 </bean>
 <bean id="jsonExceptionTranslationFilter">
 <property name="authenticationEntryPoint">
 <ref bean="formLoginAuthenticationEntryPoint"/>
 </property>
 </bean>
 <bean id="formLoginAuthenticationEntryPoint">
 <property name="loginFormUrl">
 <value>/login.html</value>
 </property>
 <property name="forceHttps">
 <value>false</value>
 </property>
 </bean>
 <bean id="anonymousProcessingFilter">
 <property name="key">
 <value>sharedsecret</value>
 </property>
 <property name="userAttribute">
 <value>anonymousUser,ROLE_ANONYMOUS</value>
 </property>
 </bean>
 <bean id="anonymousAuthenticationProvider">
 <property name="key">
 <value>sharedsecret</value>
 </property>
 </bean>
 <bean id="filterSecurityInterceptor">
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 <property name="accessDecisionManager">
 <ref bean="accessDecisionManager"/>
 </property>
 <property name="objectDefinitionSource">
 <value>
 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
 PATTERN_TYPE_APACHE_ANT
 /*.upload=IS_AUTHENTICATED_FULLY
 /*.download=IS_AUTHENTICATED_FULLY
 /index.html=IS_AUTHENTICATED_FULLY
 /=IS_AUTHENTICATED_FULLY
 /securityservice.json=IS_AUTHENTICATED_ANONYMOUSLY
 /*.json=IS_AUTHENTICATED_FULLY
 </value>
 </property>
 </bean>
 <bean id="authenticationManager">
 <property name="providers">
 <list>
 <ref bean="ldapAuthProvider"/>
 <ref bean="anonymousAuthenticationProvider"/>
 </list>
 </property>
 </bean>
 <bean id="daoAuthenticationProvider">
 <property name="userDetailsService">
 <ref bean="inMemoryDaoImpl"/>
 </property>
 </bean>
 <bean id="inMemoryDaoImpl">
 <property name="userMap">
 <value>
 demo=demo,ROLE_DEFAULT_NO_ROLES
 </value>
 </property>
 </bean>
 <bean id="jdbcDaoImpl">
 <property name="dataSource">
 <ref bean="jdbcDataSource"/>
 </property>
 <property name="usersByUsernameQuery">
 <value>SELECT first_name, last_name, 1 FROM employee WHERE first_name = ?</value>
 </property>
 <property name="authoritiesByUsernameQuery">
 <value>SELECT first_name, "DEFAULT_NO_ROLES" FROM employee WHERE first_name = ?</value>
 </property>
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 <property name="usernameBasedPrimaryKey">
 <value>true</value>
 </property>
 </bean>
 <bean id="userSearch">
 <constructor-arg index="0">
 <value>cn=users</value>
 </constructor-arg>
 <constructor-arg index="1">
 <value>(sAMAccountName={0})</value>
 </constructor-arg>
 <constructor-arg index="2">
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <property name="searchSubtree">
 <value>true</value>
 </property>
 </bean>

<bean id="jdbcDataSource"/>
 <bean id="ldapAuthProvider">
<constructor-arg>
 <bean>
 <constructor-arg>
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <property name="userSearch">
 <ref bean="userSearch"/>
 </property>
 </bean>
 </constructor-arg>
 </constructor-arg>
 <constructor-arg>
 <bean>
 <constructor-arg>
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <constructor-arg>
 <value>ou=groups</value>
 </constructor-arg>
 <property name="groupSearchDisabled">
 <value>false</value>
 </property>
 <property name="roleProvider">
 <value>LDAP</value>
 </property>
 <property name="groupRoleAttribute">
 <value>cn</value>
 </property>
 <property name="groupSearchFilter">
 <value>(member={0})</value>
 </property>
 </bean>
 </constructor-arg>
 </bean>
 <bean id="initialDirContextFactory">
 <constructor-arg value="ldap://localhost:389/dc=wavemaker,dc=com"/>
 <property name="managerDn">
 <value>cn=manager,dc=wavemaker,dc=com</value>
 </property>
 <property name="managerPassword">
 <value>7b6a43524a282c146a6b626e425c32205754</value>
 </property>
 </bean>
 <bean id="accessDecisionManager">
 <property name="allowIfAllAbstainDecisions">
 <value>false</value>
 </property>
 <property name="decisionVoters">
 <list>
 <bean/>
 <bean/>
 </list>
 </property>
 </bean>
 <bean id="roleVoter">
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 </bean>
 <bean id="autoProxyCreator">
 <property name="proxyTargetClass">
 <value>true</value>
 </property>
 <property name="interceptorNames">
 <list>
 <value>securityInterceptor</value>
 </list>
 </property>
 </bean>
 <bean id="securityInterceptor">
 <property ref="authenticationManager" name="authenticationManager"/>
 <property ref="accessDecisionManager" name="accessDecisionManager"/>
 <property name="objectDefinitionSource">
 <value>
 </value>
 </property>
 </bean>
 <bean scope="singleton" id="securityService">
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 <property name="noRolesMarkerRole">
 <value>DEFAULT_NO_ROLES</value>
 </property>
 <property name="roles">
 <list/>
 </property>
 </bean>
</beans>
4

Howto setup LDAP-Authentication for Wavemaker (Part 1)

You can leverage VMware Wavemaker to create a nice web-frontend for your users to start workflows.
(how? See the links at the end of this article!)

Typically you don’t let just everybody do that, but only identified users. So you have to implement some kind of User Authentication mechanism on the web-frontend.

The Good

Wavemaker provides included mechanisms to implement a login page, and authenticate the users against a database or a LDAP-directory, using a so called Security Service. This LDAP authentication also works against Active Directory.

The Security Service also allows a group-based distinction into different roles: you can show or hide different parts of the website to users, depending if they are in an AD-group or not.

This works very well, and is (as usual for Wavemaker  :-) ) very well documented:
http://dev.wavemaker.com/wiki/bin/Authentication
): If you get an error, remember what you learned from vCO configuration :-D e.g. the “Administrator” as Manager DN in AD is identified as “cn=Administrator,cn=Users,dc=lab,dc=local”
For troubleshooting: I’m sure you remember this post on how to troubleshoot LDAP issues?
http://www.vcoportal.de/2011/07/troubleshooting-ldap-erros-in-vco/ 

***Another Useful Site Note***
As frequent reader of this blog you remember adfind: A small, very powerful, very fast, very handy tool to figure out where and how to find objects in Active Directory…

To implement the group-checking manually you have to insert a JavaService into your project.

In the menu choose Services / Java Service:

 

In the popup you must enter a name and a package name for the java service.

 

In my case I choose the Service Name GroupAuth and LDAPGroupAuth.

Here is the java source code for that:

/**
 * This is a client-facing service class. All
 * public methods will be exposed to the client. Their return
 * values and parameters will be passed to the client or taken
 * from the client, respectively. This will be a singleton
 * instance, shared between all requests.
 *
 * To log, call the superclass method log(LOG_LEVEL, String) or log(LOG_LEVEL, String, Exception).
 * LOG_LEVEL is one of FATAL, ERROR, WARN, INFO and DEBUG to modify your log level.
 * For info on these levels, look for tomcat/log4j documentation
 */
 import com.wavemaker.runtime.RuntimeAccess;
 import com.wavemaker.runtime.security.SecurityService;

public class LDAPGroupAuth extends com.wavemaker.runtime.javaservice.JavaServiceSuperClass {
 /* Pass in one of FATAL, ERROR, WARN, INFO and DEBUG to modify your log level;
 * recommend changing this to FATAL or ERROR before deploying. For info on these levels, look for tomcat/log4j documentation
 */
 public String LDAPGroupAuth() {
 log(INFO,"ldapauth...");
 String LoginTrue= "Yes";
 String LoginFalse= "No";
 if (isUserInRole("VCOADMINS")){

 return LoginTrue;
 }else{

 return LoginFalse;
 }
 }

 private static boolean isUserInRole(String role){
 SecurityService srv = (SecurityService) RuntimeAccess.getInstance().getService("securityService");
 String[]uRoles = srv.getUserRoles();
 for(String uRole : uRoles){
 // log(INFO,"role: " + uRole);
 if(uRole.equals(role)){
 return true;
 }
 }
 return false;
 }

}

Important here: The name of the AD-group has to be typed in UPPERCASE!

Next, I had to create the “flow” of the login process, using different Layers in Wavemaker.

I copy the “Login Page” Box and the scripts into my Main site. There I work with different layer and I am able to use the “variables” on all layers.

For the integration of your GroupAuth into your project, you have to modify our “Login” Button.
During my tests for the project, I searched for a good solution to check the credentials (Username and password) against the AD Server and validate the group membership in one step. I didn’t find a, for me, robust solution.
If someone finds a better solution than the one below, please comment!  8-)

Due that circumstance, I decided to use a temporary Auth_Layer. By clicking on the “Login” button, I check the credentials, on the Login site and after checking these where valid I check the group membership.

So, here is the code for checking the AD credentials:

loginButtonClick: function(inSender) {
dojo.cookie("user", this.usernameInput.getDataValue(), {expires: 365});
 this.loginErrorMsg.setCaption("");
 wm.login(
 [this.usernameInput.getDataValue(), this.passwordInput.getDataValue()],
 dojo.hitch(this, "loginSuccess"), dojo.hitch(this, "loginFailed"));
 },
 loginSuccess: function(inResponse) {
 try{
 // This will set the currently showing layer to the AuthLayer
 main.layers1.setLayer('Auth_layer');

 } catch(e) {
 console.error('ERROR IN loginSuccess: ' + e);
 }
 },
 loginFailed: function(inResponse) {
 this.loginErrorMsg.setCaption("Invalid username or password.");
 this.usernameInput.focus();
 },

When the user credentials where valid, the layer is changed to the “Auth_Layer”.

On this layer, the group membership is checked. Here is the code for the check (executed in the “onShow()”-Event of this Layer):

loginButtonClick: function(inSender) {
 dojo.cookie("user", this.usernameInput.getDataValue(), {expires: 365});
 this.loginErrorMsg.setCaption("");
 wm.login(
 [this.usernameInput.getDataValue(), this.passwordInput.getDataValue()],
 dojo.hitch(this, "loginSuccess"), dojo.hitch(this, "loginFailed"));
 },
 loginSuccess: function(inResponse) {
 try{
 // This will set the currently showing layer to the AuthLayer
 main.layers1.setLayer('Auth_layer');

 } catch(e) {
 console.error('ERROR IN loginSuccess: ' + e);
 }
 },
 loginFailed: function(inResponse) {
 this.loginErrorMsg.setCaption("Invalid username or password.");
 this.usernameInput.focus();
 },

So if the group membership of the user is okay, the user is redirected to the “Request_Layer”. If the group membership is not okay, the user is redirect to the “Denied_Layer”.

In sum, the system provides for three different conditions:

  • Username or Password is wrong: This shows an small “login unsuccessful”-message directly in the login-box
  • Username / Password is correct (so he is logged-in from the Wavemaker Security Service perspective), but the user is NOT in the AD-group. Then he’s redirected to the “Denied_Layer”.
  • Username / Password is correct (so he is logged-in from the Wavemaker Security Service perspective), AND he is in the AD-group. Then he’s redirected to the “Request_Layer”, which for instance contains the buttons that trigger Orchestrator Workflows.

The Ugly

Given some restrictions of the underlying mechanisms used for the Security Service implementation in Wavemaker, it only supports groups within one Organizational Unit (OU) in Active Directory.
However, there is a workaround for this, expect Part 2 of this article soon :mrgreen:

References

To give you an idea about it looks like at the end of the day, download the project below!
(It’s a Wavemaker 6.4 exported project, should be directly importable. Just make sure to adjust the LDAP-Settings of the Security Service!)

Aaaaand, some links:
http://www.vcoportal.de/2011/11/using-wavemaker-as-web-frontend-for-vco/
http://www.virtuallyghetto.com/2011/12/leveraging-vcd-vco-wavemaker-part-1.html
http://www.virtuallyghetto.com/2011/12/leveraging-vcd-vco-wavemaker-part-2.html
Wavemaker-LDAP-Authentication

Wavemaker-LDAP-Authentication
vCO_WM_LDAP.1.Alpha.zip
160.2 KiB
Details...
8

Using Wavemaker as Web-Frontend for vCO

UPDATE 23. Nov. 2011: Additional Reference: Christian Johannsen posted a great step-by-step example for Wavemaker & vCO on http://mighty-virtualization.blogspot.com/2011/11/vco-wavemaker-your-cloud-webservice.html

There are different ways to create a web-based frontend for Orchestrator:

  • Webviews (included, provide integrated finder for inventory objects BUT old, hard to learn, deprecated, don’t bother to start with…)
  • Perspectives (based on webviews, very easy to use, way to go for quick-wins)
  • build your own (call Workflows via the SOAP-based API of Orchestrator)

(for more details, see this post)

Now, rumors are out there for a long time, it seems that Wavemaker is a hot candidate as main technology for the web-based stuff in future (it was mentioned at VMworld and in the forums… Yohooo!).

The Video

To get started, see following screencast…
Disclaimer: Starting at 6:30 it gets very dirty! Do not let your children nor your VMware Support Guy watch this unattended, and only try this at home! :mrgreen:

Wavemaker as Web-Frontend for VMware vCenter Orchestrator – Sneak Preview from Joerg Lew on Vimeo.

(I used the current 6.4.2 BETA of Wavemaker against vCO 4.1, but should work as well with slightly different versions of both components…)

So, why is Wavemaker a perfect fit (The GOOD…)?

It allows to to create nice-looking websites with a real bunch of logic without the need for tooooo much knowledge about web-development. (Orchestrator allows to create complex automation for your complete IT-Infrastructure without the need for tooooo much knowledge about software development)

It defines the information flow between different elements via a parameter binding semantic. (How do you pass information through a workflow in Orchestrator??)

You can drag&drop content elements from the palette to your actual website, and program additional logic in JavaScript (in the vCO you can drag&drop…. Well, you get the point…)

It uses the same platform. (see the dirty end of the video 8-O ), so a good integration is possible.

It’s the same company. (<EVILMODEON>So if VMware learned something from the  **yourAdjectiveHere** acquisition of Dunes some time ago, this time they get synergy earlier!!!<EVILMODEOFF>)

Drawbacks (The BAD…)

As external system, your wavemaker frontend has to call workflows via the API. So it is some effort to pass input parameters to the workflow, and it is a real bunch of effort (you don’t use “pain-in-the-ass” in a public blog :-? ) if your workflow needs inventory objects as input.

So, in the current version you are bound to the features, the “usability”, and the limits of vCO’s current SOAP-API.

The Future (NOT ugly, quite the opposite!)

Two things on the horizon might make the Wavemaker<=>vCO-Integration perfect in future:
First, a new API in a future version of vCO could make the usage of inventory-objects as inputs easier;
Second, a bunch of pre-built vCO-related elements in the Wavemaker Palette could make the development of the web-frontend easier (compare it to the idea, not the complexity and not-documentation, of the vCO-related Tapestry objects in Webviews)….
=> Go vCO-Team! Go Wavemaker!

References

To get started with Wavemaker and the vCO-SOAP-API, see following links:

…and:

The way shown in the video using the SOAP-interface directly with a WebService-Variable in Wavemaker is not the only way (and maybe not the best one for every use-case). You can also create your own Java stubs (see the examples-zip in the Orchestrator Documentation), and use a “plain old” JavaService Variable against them in Wavemaker.

Summary

So in general, despite some hurdles due to the limits of the current SOAP-API, Wavemaker allows you to create good looking webinterfaces for Orchestrator Workflows. And it’s absolutely worth to dig into it, because this seems to be THE technology for webbased vCO-Access in the future.

2

Welcome back, Perspectives! (or: How to provide webbased UI for vCO without programming?)

VMware Labs published the Perspectives Plugin for vCO. It allows you to provide a webinterface for users to start and monitor Workflows. It is quite flexible, you can define different “perspectives” (list of workflows) for different user groups. And the best: All of this can be done without programming any single line of HTML/JavaScript-Code (The setup itself is again done by Workflows).

To download the Perspectives Plugin:
http://labs.vmware.com/flings/perspectives-plug-in-for-vcenter-orchestrator

The Documentation:
http://labs.vmware.com/download/141/

For a further description and configuration example:
http://www.vcoteam.info/newsflash/vmware-labs-released-the-perspectives-plug-in.html
http://www.vcoteam.info/learn-vco/getting-started-with-perspectives-webview.html

To get an overview which Perspectives you already have created and which Workflows are provided in each, go to the Inventory-Tab of your vCO-(Smart-)Client to get a nice tree-view:

Be aware, that (as all Flings from VMware Labs) the Plugin is under Technical Preview License and therefore not supported.

For other alternatives to provide users a webbased interface to the Orchestrator, read this discussion…

Page 1 of 212