Getting Started Developing Microservices

getting the sources

The source of this tutorial is available on GitHub at https://github.com/openmsa on Microservices/Tutorials/LINUX/Generic/Tutorial1. Microservices can be used to manage a wide variety of services on numerous types of devices, such as:

Overview

This tutorial explores the design and development of a Microservice. Microservices can be used to manage a wide variety of services on numerous types of devices, such as:

  • network equipment (routers, switches, UTM, etc.)
  • virtualization infrastructure managers (VMWare, AWS, Openstack, etc.)
  • Linux servers

Lab Setup

The first step in Microservice design and development is to have a device to manage.

This tutorial assumes you have a properly configured, running MSActivator.

As a first example of Microservices, we will start with managing a Linux server. There are plenty of Linux distribution options, and this tutorial will use a Linux Centos 6.

Use the device creation wizard to create a device and ensure that it's a Linux/generic.

Image

For "Management IP address", enter the IP address of the managed Linux, and make sure it's accessible from the MSActivator.

"Authentication" uses the root account, which is suitable for a lab but in a production environment you should use a more restricted user account (i.e. a manager account).

Once created, activate the device using the "Initial provisioning" option in the "Actions" drop down list, and wait 1-2 minutes until the device is marked as "UP" and the asset values are filled. This means that the MSActivator monitoring module can ping the Linux and can also connect with SSH.

Microservice Design

Now that there is a device available (Linux Centros 6), we can create our first Microservice.

The first step is to create a new Microservice and associate it to the managed Linux device.

If you don't know how to create a new Microservice and associate it to a device, refer to OBMF Objects Definition.

Once you have created a new Microservice (named "user") in the repository and attached it to your device, you can begin the design and implementation.

Design and Implementation

On Linux Centos 6, the CLI command to list the users is "cat /etc/passwd". To create a new user it's "useradd", and to delete a user it's "userdel".

[root@managed-linux ~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
...
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
oprofile:x:16:16:Special user account to be used by OProfile:/home/oprofile:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin

The list of users in /etc/passwd contains the system users that we want to exclude from the scope of the Microservice. We'll cover this later in this tutorial.

Import the Users with the IMPORT Function

The result of the CLI command "cat /etc/passwd" is composed of a line with the format:

Image

  1. Username: Used when user logs in. It should be between 1 and 32 characters in length.
  2. Password: An "x" character indicates that an encrypted password is stored in /etc/shadow file. Please note that you need to use the passwd command to compute the hash of a password typed at the CLI, or to store/update the hash of the password in /etc/shadow file.
  3. User ID (UID): Each user must be assigned a user ID (UID). UID 0 (zero) is reserved for root. UIDs 1-99 are reserved for other predefined accounts. UIDs 100-999 are reserved by the system for administrative and system accounts/groups.
  4. Group ID (GID): The primary group ID (stored in /etc/group file)
  5. User ID Info: The comment field. Allows you to add extra information about the users, such as user’s full name, phone number etc. This field used by finger command.
  6. Home Directory: The absolute path to the directory the user will be in when they log in. If this directory does not exists then users directory becomes /.
  7. Command/Shell: The absolute path of a command or shell (/bin/bash). Typically, this is a shell. Please note that it does not have to be a shell.

Now let's build the IMPORT function with the parsers to extract the information listed above.

First we have to decide how the Microservice ID (the mandatory variable name "object_id") will be extracted. In this case, since the username is unique on Linux, the obvious choice is to use the username field as the object_id.

The regular expression to extract the fields from the result of "cat /etc/passwd" is

@(?[^:]+):(?[^:]+):(?[^:]+):(?[^:]+):(?[^:]*):(?[^:]+):(?[^:]+)@

Note: it may be useful to use an online regular expression tester when developing and testing regular expressions. One online tester can be found here: http://lumadis.be/regex/test_regex.php (see reference below)

Image

Once validated, this regular expression can be used in the field "Micro service identifier extractor" of the IMPORT function builder:

Image

Note that the variables such as object_id, password, etc. were automatically created by the Microservice designer. You can change the display name of the variables, reorder them, and eventually make some of them read only (for instance, you can leave the user_id, group_id and shell as read only and simply display the one generated by the Linux CLI). The password can be set as not visible to simplify the display.

Save your work, run the synchronization, and view at the result.

Image

Add and Remove Users with the CREATE and DELETE Functions

On linux, the CLI command to add a user is:

useradd -m -d HOME_DIR -c COMMENT -p PASSWORD LOGIN

and to delete a user is:

userdel -f -r  LOGIN
          

Since it's possible to set the password as a parameter of the user creation, you need to modify the definition of the variable "password" and make it visible and mandatory (but only in the edit view).

Image

You are now ready to implement the CREATE:

useradd -m -d {$params.home_dir} -c "{$params.comment}" -p {$params.password} {$params.object_id}

and the DELETE:

userdel -f -r {$users.$object_id.object_id}
          

Note the use of the syntax {$users.$object_id.object_id} in the implementation of the DELETE.

$users is the name of the Microservice definition file as created in the repository: users.xml. This syntax is used to get values from the MSActivator database, where Microservice instances are stored. The syntax has to be used when implementing a DELETE because the DELETE must delete the entry from the database AND remove the configuration from the device (in this case we want to delete a user).

This syntax is also widely used when implementing the READ and LIST (See How to Use List & Read)

Going Further

With this simple implementation you can manage users on a Linux system, but there are some additional use cases that you may want to address:

  • Is it possible to ignore the system users when importing (ex: bin, daemon, adm,...)?
  • What if no comment is provided?
  • What if no home dir is provided?

How to Ignore the System Users

In order to ignore system users during the import, you have to find criteria to help differenciate system users from the users created by the system admin. You can chose to ignore all users that don't have the home dir under /home. The regular expression would then look like:

@(?[^:]+):(?[^:]+):(?[^:]+):(?[^:]+):(?[^:]*):(?/home/.+):(?[^:]+)@
          

This regular expression will exclude all user that don't have a home dir under /home, but the system users below will still be imported:

oprofile:x:16:16:Special user account used by OProfile: /home/oprofile:/sbin/nologin
          

Since the shell isn't part of the parameters that we have exposed in the creation form, you can decide to import the user that have /bin/bash as shell:

@(?[^:]+):(?[^:]+):(?[^:]+):(?[^:]+):(?[^:]*):(?/home/.+):/bin/bash@
          

In this case, the variable shell is no longer needed, so you can remove it from the list of the variables. You also have to update the CREATE function to make sure that the home dir will always be under /home, and you have to make sure that the variable home_dir is read only.

useradd -m -d /home/{$params.object_id} -c "{$params.comment}" -p {$params.password} {$params.object_id}

How to Handle Optional Empty Variables?

The comment is an optional parameter, so you need to make sure that the execution of the CLI command "useradd" will not fail if no comment is passed as a parameter.

This can be acheived with a bit of scripting in the CREATE function:

{if empty($params.comment)}
useradd -m -d /home/{$params.object_id} -p {$params.password} {$params.object_id}
{else}
useradd -m -d /home/{$params.object_id} -c "{$params.comment}" -p {$params.password} {$params.object_id}
{/if}