Getting Started Developing Microservices

Overview

This tutorial will walk you through the design and development of your first microservice. Microservices can be used to manage a wide variety of services on numerous type of devices:

  • network equipment (routers, switches, UTM,...)
  • virtualisation infrastructure manager (VMWare, AWS, Openstask,...)
  • linux server

Lab setup

To start with Microservice design and development the first step is to have a device to manage.

Here the assumption is that you have a running MSActivator, properly configured. If you don't please check the page MSA Configuration.

The easiest way to start with Microservice is to start with managing a Linux server. There are plenty of Linux distribution and this tutorial will use a Linux Centos 6.

Use the device creation wizard to create a device, make sure that it's a Linux/generic

ManagedLinuxDevice.png

Management IP address should be the one of the managed linux and it should be accessible from the MSActivator.

Authentication uses the root account which is fine for a lab but in a real production environment you'd probably have to use a more restricted user account.

Once created, activate the device with the initial provisioning and wait 1-2 minutes until the device is marked as UP and the asset values are filled. This means that the MSA can ping the Linux and can also connect with SSH.

Microservice design

As a first example, we are going to go through the design and implementation of a Microservice for managing users on a Linux centos6.

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

If you don't know yet how to create a new Microservice and associate it to a device you can refer to this documentation: OBMF Objects Definition

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

Design

on Centos 6, the CLI to list the users is "cat /etc/passwd" and to create a new user: "useradd" and to delete: "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 user in /etc/passwd contain the system users that we want to exclude from the scope of the Microservice. We will see how to do this later in this tutorial.

Import the users with the IMPORT function

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

passwd-file.png
  1. Username: It is used when user logs in. It should be between 1 and 32 characters in length.
  2. Password: An x character indicates that encrypted password is stored in /etc/shadow file. Please note that you need to use the passwd command to computes 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 and UIDs 1-99 are reserved for other predefined accounts. Further UID 100-999 are reserved by 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. It allow you to add extra information about the users such as user’s full name, phone number etc. This field use 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.

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 our case, since the username is unique on Linux, the obvious choice will be to use the username field as the object_id.

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

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

to develop and test regular expression it is possible to use online regular expression tester such as http://lumadis.be/regex/test_regex.php:

regexp_tester.png

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

import_users_1.png

note that the variables such as object_id, password,... were automatically created by the Microservice designer. You can change the display name of the variables, reorder them, and eventually make some of them as read only (for instance, we can decide to leave the user_id, group_id and shell as read only and simply display the one generated by the Linux CLI). The password, since it's not showing anything useful, can be set as not visible.

Save your work, run the synchronisation and look at the result.

mport_users_1_result.png

Add and remove users with the CREATE and DELETE functions On linux, the CLI to add a user is:

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

and to delete a user:

userdel -f -r  LOGIN

since it's possible to set the password as a parameter of the user creation, we need to modify the definition of the variable "password" and make it visible and mandator but only in the edit view.

user_microservice_definition.png

we are 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.

The $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 MSA database where Microservice instaces 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 our case we want to delete a user).

This syntax is also widely used when implementing the READ and LIST ( How to read configuration items from the CMDB (READ & LIST))

Going further

With this simple implementation we can manage users on a Linux system but there are some use case that we 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 we have to find criteria to help differenciate system users from the users created by the system admin. We can chose to ignore all users that don't have the home dir under /home. The regex would look like:

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

This regex will exclude all user that don't have a home dir under /home but the system user 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, we can decide to import the user that have /bin/bash as shell:

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

In that case, the variable shell isn't necessary any more so we can remove it from the list of the variables. We alse have to update the CREATE function to make sure that the home dir will always be under /home and we 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 we need to make sure that the execution of the CLI useradd will not fail if no comment is passed as 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}