Home > Blogs > VMware vApp Developer Blog > Monthly Archives: January 2010

Monthly Archives: January 2010

Adding Linux Management Service to Virtual Appliance

VMware Studio 2.0 allows author to add their own in-guest services that will show up as another tab in the appliance web interface. If you want to add additional appliance configuration capabilities or want to consolidate appliance and application configuration into single web interface, this blog will show how to achieve the same easily. 

Lets create a simple in-guest service, that can run
arbitrary commands on the appliance. Since it is allowed to run arbitrary
commands we need to ensure that the service has authentication and can only be
invoked by a user with proper credentials.

Eclipse Plugin for Studio (see installation instructions at VMware Studio Eclipse Plugin
) provides an easy way to create and build Management Service. You can also
create the management service by hand by constructing the same directory
structure, and having a service.xml please see VMware Studio Developer Guide
for details of the format of the Management Service.

Create an new Project, and pick “VMware Studio Linux
Management Service Project” as shown below.

001

002

Enter details about your service.

003
 This will create a directory structure for the service as
shown below.

 004

 Generated service.xml has the details of the service, you
can modify this to fit your needs. If there are any external package
dependencies you can add them in service.xml.

 

<?xml version="1.0"
encoding="UTF-8"?>

<service>

  <name>myservice</name>

  <version>1.0.0.0</version>

  <description>My Service to
run a command
</description>

  <!– Dependencies

   <requires>

      <packages>vmware-studio-vamiservicebase</packages>

     
<services>network,system</services>

   </requires>

   –>

</service>

View.xml in the view folder points to what will be shown to the user in the
management tab of the VM, by default it points to an index.html page you can
change this to any other content. You will put all your html related content
for the service in the view folder, they will be placed in the
/opt/vmware/share/httpd/service/myservice folder on the Appliance.


<service>

      <title>My Service</title>

      <content type="url"
url="index.html" />

</service>


For our service we would want to invoke some command on the
Appliance and show the result to the user. Lets add the necessary html to take
input from the user in the index.html page.

<script language="JavaScript">

// Obtain the
vami object, please read documentation for various functions that can be
executed on vami

var vami =
parent.vami;

// Callback to
take the command result and show to the user

function
commandOutput(commandresult) {

      document.getElementById('output').value =
commandresult;

}

function runCommand() {

      var commandToRun =
document.getElementById(
'command').value;

      //cgi files are placed are served from
/service/myservice/cgi/

      var cgiToInvoke = '/service/myservice/cgi/backend.py?command=' + commandToRun;

      //Invoke vami.io to perform a httpGet
request with basic authentication and callback with the result to
commandOutput 

      vami.io.httpGet(true, true, 'Running the
command..'
, cgiToInvoke, commandOutput);

}

</script>

<h3>Sample CGI</h3>

<p>Run any command
on the appliance and get the results.
</p>

Enter the command

<input type="text"
name="command" id="command"
size="50" value="pstree">

<button type="submit"
onclick="runCommand()">Run</button>

<p><textarea class="output"
id="output" readonly="true">Command output >>></textarea>

</p>

</body>


vami.io.httpGet is a VAMI Web API that does AJAX call to the back end
and callbacks a function when it is done. Refer to VMware Studio Developer Guide
for detailed list of VAMI Web API.

 

We need to take care of running the actual command on
the Appliance, you may wish to write the backend in any backend technology you
may wish, you can even write it as a CIM Provider on sfcb.  

 

We will write our backend in python, lighttpd on the
appliance is already configured to work with python. If you would like to write
the backend in php, perl or ruby make sure you add the necessary lighttpd.conf
file for the service to configure lighttpd to work with those technologies.

 

Our backend code in python will simply invoke the command
return the result.

 

#

# Back end code
that will be executed to return data to the user

def backend_code():

   #return http header, the extra
empty line is required

   print 'Content-Type: text/html'

   print 'Status: 200'

   print 

   form = cgi.FieldStorage()

   #Obtain the form fields

   command = form['command'].value

   #Run the command as passed by the user
with current directory set to /root

   pobj = subprocess.Popen(command, bufsize=1, shell=True,

                       stdout=subprocess.PIPE,

                     stderr=subprocess.STDOUT,
cwd=
'/root')

  

   #Output of the command is sent back to
the user

   while True:

      line = pobj.stdout.readline()

      if not line:

         break

      print line.strip()

   sys.exit(0)

 

When we are invoking the backend we asked VAMI to do basic
http authentication, using vami.io.httpGet(true , we would need to add
the necessary checks in our backend code that we will only execute a given command
if user is authenticated. User name and sessionid is sent as part of the http
basic authorization, we can use this information to make a call on the SFCB
server to make sure that user is authorized.

 

def autentication_failure():

   print 'Content-Type:
text/html'

   print 'Status: 401'

   print 'WWW-Authenticate: Basic
realm="Authentication required"'
  

   print

   sys.exit(1)

 

if "HTTP_AUTHORIZATION" in os.environ:

   #of the form 'HTTP_AUTHORIZATION':
'Basic cxadsfas='

   http_auth = os.environ["HTTP_AUTHORIZATION"].split(" ")[1]

   user, sessionid =
base64.decodestring(http_auth).split(
":", 1)

   #Authenticate user using CIM server to
process username,password

   try:

      cliconn = pywbem.WBEMConnection('http://localhost:5488', (user,
sessionid))

      cliconn.EnumerateInstanceNames('VAMI_ComputerSystem')

   except Exception, e:

      autentication_failure()

   backend_code()

  

else:

   autentication_failure()

 

 

To Build the Service, right click
build.xml and select run as “Ant Build”, this will create a tar.gz.

 

005

 

You can now
include this service as part of your appliance, please refer to “Importing a
Management Service” section in VMware Studio Developer Guide and when you do, your final appliance web UI will be as shown below.

006 

 Download myservice.zip to get the full details of the code and the eclipse project.