This wiki is obsolete, see the NorduGrid web pages for up to date information.

Developing services

From NorduGrid
Jump to navigationJump to search

Developing services

Security

Linux FHS

The Linux Filesystem Hierarchy Standard dictates where files should go

init.d

logrotate.d

cron.d

Signals

Signals are sent from users or the system to your service, the important ones that need to be handled are:

  • HUP - when it should reload configurations and reopen files (logs, etc)
  • TERM - the nice way of terminating a program, handling this needs to end up with a exit(0) or exit(1)

In C

Minimal program for handling a SIGHUP

 #include <signal.h> // signal handling in this header
 #include <stdio.h>
 
 void signal_handler(int sig){
   switch(sig){
     case SIGHUP:
       printf("hangup signal catched\n");
       break;
   }
 }
 
 int main(int argc, char** argv){
   signal(SIGHUP,signal_handler); /* catch hangup signal */
   while(1) sleep(1);
 }

In Perl

In Python

In Bash/Sh

Creating a Daemon/Service

Adding a new service to the code tree

Starting a new component be it a new service or new protocol etc. Is quite easy though there are some rules / guideline one must follow. We will use an example of a new service but the instructions here can be applied to most other parts of the code. First find the appropriate location (for services it is in src/services):

 cd src/services
 mkdir myservice
 cd myservice

The first thing you should do is to add a README file. The README file should give a short explanation about the services. The README file is mandatory. The second file you should add is Makefile.am. This file is used by Automake (part of Autotools) and is a recipe for how to build your component. Here is a good starting template:

 # For Unit testing
 SUBDIRS = $(TEST_DIR)
 DIST_SUBDIRS = test
 
 # The service
 pkglib_LTLIBRARIES = libmyservice.la
 libmyservice_la_SOURCES  = myservice.cpp myservice.h
 libmyservice_la_CXXFLAGS = $(GLIBMM_CFLAGS) $(LIBXML2_CFLAGS) -I$(top_srcdir)/include
 libmyservice_la_LIBADD   = $(top_srcdir)/src/hed/libs/loader/libarcloader.la $(top_srcdir)/src/hed/libs/message/libarcmessage.la $(top_srcdir)/src/hed/libs/security/libarcsecurity.la \
                             $(top_srcdir)/src/hed/libs/common/libarccommon.la $(GLIBMM_LIBS) $(LIBXML2_LIBS)
 libmyservice_la_LDFLAGS  = -no-undefined -avoid-version -module

The first paragraph is needed for unit testing which is explained on ARC1/Unit Testing. The second paragraph is the recipe for creating the "myservice" service plugin.

Once we are ready to build the service we must inform Autotools about the new component. This is done in the toplevel configure.ac. Towards the bottom of this file there is a line starting with

 AC_CONFIG_FILES

List your directories with appended "/Makefile" below in the list:

 ...
 src/services/Makefile
 src/services/test/Makefile
 ...

Autotools will create Makefile.in and Makefile from your Makefile.am recipe.

We have created a service which installs a file through the line:

 pkglib_LTLIBRARIES = libmyservice.la

We need to explicitly tell the packaging tools about this file. For RPM packaging this is done in the toplevel:

 nordugrid-arc.spec.in

while for DEB packaging there is a file per service:

 debian/nordugrid-arc-newservice.install

We should now be ready to test that our service is properly integrated in the build structure. Go to the top-level directory and do:

 ./autogen.sh  # Needed if you modify Makefile.am
 ./configure
 make
 make check    # Run the Unit tests
 make install DESTDIR=/tmp/myinstall

If all went well you should be able to find your new service installed under /tmp/myinstall.

Please respect your fellow coders and make sure that your service compiles correctly.

Example code for a new service within HED

HED is the Hosting Environment Daemon and is a container for services. See "The Hosting Environment of the Advanced Resource Connector middleware" for a general description of it. For configuration information and how Message Chain Components (MCCs) work please read "WS-ARC service configuration manual".

At a minimum a HED service must:

  • Define a sub-class of RegisteredService
  • Implement the process() method - this is the method that is called when the service is invoked
  • Provide the factory method get_service which enables HED to create an instance of the service
  • Define the PLUGINS_TABLE_NAME array with this service
  • Optionally define a RegistrationCollector() method to enable the service to be registered in the information system

The following code is a minimal example of such a service

NewService.h

#include <arc/infosys/RegisteredService.h>
#include <arc/message/Message.h>
#include <arc/XMLNode.h>
#include <string>

namespace NewService {

class NewService: public Arc::RegisteredService {

 public:
   NewService(Arc::Config *cfg);
   virtual Arc::MCC_Status process(Arc::Message &inmsg, Arc::Message &outmsg);
   bool RegistrationCollector(Arc::XMLNode &doc);
};

} // namespace NewService

NewService.cpp

#include <arc/message/MessageAttributes.h>
#include <arc/message/PayloadRaw.h>
#include <arc/message/PayloadStream.h>

namespace NewService {

static Arc::Plugin *get_service(Arc::PluginArgument* arg)
{
   Arc::ServicePluginArgument* srvarg =
           arg?dynamic_cast<Arc::ServicePluginArgument*>(arg):NULL;
   if(!srvarg) return NULL;
   NewService* s = new NewService((Arc::Config*)(*srvarg));
   return s;
}

NewService::NewService(Arc::Config *cfg) : RegisteredService(cfg) {}

Arc::MCC_Status NewService::process(Arc::Message &inmsg, Arc::Message &outmsg) {
   return Arc::MCC_Status(Arc::STATUS_OK);
}

bool NewService::RegistrationCollector(Arc::XMLNode &doc) {
   Arc::NS isis_ns; isis_ns["isis"] = "http://www.nordugrid.org/schemas/isis/2008/08";
   Arc::XMLNode regentry(isis_ns, "RegEntry");
   regentry.NewChild("SrcAdv").NewChild("Type") = "org.nordugrid.execution.newservice";
   regentry.New(doc);
   return true;
}

} // namespace NewService

Arc::PluginDescriptor PLUGINS_TABLE_NAME[] = {
   { "newservice", "HED:SERVICE", 0, &NewService::get_service },
   { NULL, NULL, 0, NULL }
};

The Arc::Config object passed to the constructor contains configuration information for that service. One persistent instance of the service class is created upon HED startup and is used for the lifetime of the HED process. When a client invokes the service, HED calls the process method of the service instance. The inmsg Message in process() contains the XML message sent to the service from the client and in this method the actions should be defined depending on the client requests. outmsg is what is sent back to the client and should be filled appropriately. For working examples of services one can browse the src/services folder of the ARC subversion repository.