Documentationcurrent version
Help us improve the docs by fixing typos and proposing enhancements.

Nikita

Control Flow

Nikita runs every action sequentially. This behavior ensures there are no conflicts between two commands executed simultaneously. Moreover, this sequential nature is aligned with SSH which executes one command at a time over a given connection.

Sequential execution

Since an action may contain child actions, the way Nikita runs is similar to how you might want to traverse a file system. For every action scheduled, Nikita will run its children recursively before passing to the next scheduled action.

Let's imaging we want to install 2 packages my_pkg_1 and my_pkg_2 before modifying a configuration file:

nikita
.call(function() {
  this.service('my_pkg_1')
  this.service('my_pkg_2')
})
.file.yaml({
  target: '/etc/my_pkg/config.yaml',
  content: { my_property: 'my value' }
})

The actions will be executed in this sequence:

  • (1) call
    • (2) service for my_pkg_1
    • (3) service for my_pkg_2
  • (4) file.yaml

This tree-like traversal is leverage by the header metadata and the log.cli action to display a report to the terminal.

nikita
.log.cli({pad: {header: 20}})
.call({
  $header: 'Packages'}, function() {
  this.service({
    $header: 'My PKG 1'  }, 'my_pkg_1')
  this.service({
    $header: 'My PKG 2'  }, 'my_pkg_2')
})
.file.yaml({
  $header: 'Config',  target: '/etc/my_pkg/config.yaml',
  content: { my_property: 'my value' }
})

Will output like this:

localhost   Packages : My PKG 1  ✔  1ms
localhost   Packages : My PKG 2  ✔  1ms
localhost   Packages             ✔  3ms
localhost   Config               ✔  10ms

Note, to make this example working, you have to change package names to real packages supported by your OS.

Interrupting the execution

The native Nikita scheduler interrupts the global Nikita session in case of failure of any action. This behavior prevents error propagation to the next actions. In the following example, the second action will not be executed because the first one throws an exception:

nikita
// Throws an exception
.call(() => {
  throw Error('Oh my God!')
})
// Is not executed
.call(() => {
  console.info('I am not executed.')
})

However, the session can be preserved by catching the exception thrown by action Promise. The example below uses the try...catch statement to handle the exception:

nikita
.call(async function() {
  try {    // Throws an exception    await this.call(() => {      throw Error('Oh my God!')    })  } catch(err) {    console.info(err.message)  }  // Is executed
  this.call(() => {
    console.info('I am executed the error is catched.')
  })
})

Condition and status

The execution flow can be controlled by mixing conditions and output such as status and error returned with Promise.

Note, Nikita's actions always return Javascript Promise. To access the action output, you have to call an asynchronous function and "await" for the result of Promise.

The example below demonstrates the combination of the status output variable and the if condition. The second action is executed if the status is true:

nikita
.call(async function() {
  // Get status of the 1st action
  const {$status} = await this.execute({    command: 'echo catchme | grep catchme' // Returns status true
  })
  // Run the 2nd action if status is true
  this.call({
    $if: status  }, function(){
    console.info('The condition passed, because the status is true')
  })
})

In the following example, the second action is executed if the first one is failed. To prevent throwing an exception the relax behavior is enabled:

nikita
.call(async function() {
  // Get error of the 1st action
  const {error} = await this.execute({    $relax: true,  // Don't throw an error if occured
    command: 'echo missyou | grep catchme' // fails
  })
  // Run the 2nd action if error
  this.call({
    $if: error  }, function(){
    console.info('The condition passed because an error occured')
  })
})
Edit on GitHub
Navigate
About

Nikita is an open source project hosted on GitHub and developed by Adaltas.