3.2. RE-CORE¶
The core is essentially a finite state machine (FSM) hooked into a message bus and a database.
The core oversees the execution of all release steps for any given project. The core is separate from the actual execution of each release step. Execution is delegated to the worker component.
3.2.1. Running From Source¶
$ . ./hacking/setup-env
$ re-core -c ./examples/settings-example.json
3.2.2. RE-CORE Configuration¶
Configuration of the server is done in JSON. You can find an example configuration file in the examples/ directory.
You must point to a specific configuration file using the -c command-line option to start the FSM:
$ re-core -c settings.json
Descriptions of all settings directives:
Name | Type | Parent | Value |
---|---|---|---|
LOGFILE | str | None | File name for the application level log. Include the full path to write the log somewhere else |
LOGLEVEL | str | None | Logging threshold, default: INFO. Acceptable values: DEBUG, INFO, WARN, ERROR, CRITICAL |
RELEASE_LOG_DIR | str | None | Directory for per-release logging (default: None) |
TRIGGERS | str | None | Path to a trigger step definition file |
MQ | dict | None | Where all of the MQ connection settings are |
SERVER | str | MQ | Hostname or IP of the server |
NAME | str | MQ | Username to connect with |
PASSWORD | str | MQ | Password to authenticate with |
QUEUE | str | MQ | Queue on the server to bind |
VHOST | str | MQ | VHost to connect to on the server |
PORT | int | MQ | AMQP connection port (default 5672 for non-ssl, 5671 for ssl) |
SSL | bool | MQ | If the AMQP connection should be SSL/TLS secured (default false) |
DB | dict | None | Where all the DB connection settings are |
SERVERS | list | DB | List of all of the MongoDB hostname/IPs |
DATABASE | str | DB | Name of the MongoDB database |
NAME | str | DB | Username to connect with |
PASSWORD | str | DB | Password to authenticate with |
PHASE_NOTIFICATION | dict | None | Notifications that will always happen in a phase |
TABOOT_URL | str | PHASE_NOTIFICATION | URL with %s to taboot tailer EX: http://example.com/taboot/%s/ |
TOPIC | str | PHASE_NOTIFICATION | The topic (routing key) to send notification on. EX: notify.irc. |
TARGET | list | PHASE_NOTIFICATION | The targets to send the notification to. EX: ["#mychannel", "auser"] |
PRE_DEPLOY_CHECK | list | None | The yes/no checks to make prior to deployment (see below for more information) |
POST_DEPLOY_ACTION | list | None | Steps which are ran after the playbook has been ran (see below for more information) |
For a full example see example-config.json.
3.2.2.1. MQ Configuration Notes¶
There are two optional parameters in the MQ configuration section: PORT, and SSL. Their defaults are shown below:
- PORT - 5672 (rabbitmq no-ssl)
- SSL - false
If SSL is not set (or is false) then re-core uses the default rabbit MQ port (5672), unless a port has been specified in the config file. If SSL is set to true then re-core uses the RabbitMQ SSL port (5671), unless a port has been specified in the configuration file.
Simply put, you don’t need to set SSL or PORT unless:
- You want to enable SSL (in which case, set SSL to true in the config file)
- You are running RabbitMQ on non-standard ports.
Here’s a bare-minimum MQ configuration section:
1 2 3 4 5 6 7 8 9 10 | {
"MQ": {
"EXCHANGE": "my_exchange",
"NAME": "username",
"PASSWORD": "password",
"QUEUE": "re",
"SERVER": "amqp.example.com",
"VHOST": "/"
}
}
|
Note that PORT and SSL are not set. Therefore this will open an unencrypted connection to Rabbit MQ using the default port (5672).
Here’s a bare-minimum MQ configuration file for an encrypted connection:
1 2 3 4 5 6 7 8 9 10 11 | {
"MQ": {
"EXCHANGE": "my_exchange",
"NAME": "username",
"PASSWORD": "password",
"QUEUE": "re",
"SERVER": "amqp.example.com",
"SSL": true,
"VHOST": "/"
}
}
|
Note on line 8 that we set SSL to true (remember, it’s lower-case “true” in JSON files) and we are not setting the port. In this case the port is automatically set to 5671.
And now a non-standard configuration:
1 2 3 4 5 6 7 8 9 10 11 12 | {
"MQ": {
"EXCHANGE": "my_exchange",
"NAME": "username",
"PASSWORD": "password",
"PORT": 5672,
"QUEUE": "re",
"SERVER": "amqp.example.com",
"SSL": true,
"VHOST": "/"
}
}
|
In this confusing and non-standard configuration we are connecting to an SSL enabled RabbitMQ server which is listening for SSL connections on port 5672, a port which is normally reserved for non-SSL connections.
3.2.3. RE-CORE Deployment¶
3.2.3.1. From RPM Package¶
- Install the re-core RPM package
- Create a settings.json file (use example-config.json as a starting point)
- Start the core:
$ re-core -c ./settings.json
3.2.3.2. From Source¶
- Change into the directory you cloned re-core into
- Run screen
- Update your re-core config file with appropriate values
- Update your paths by running: . ./hacking/setup-env
- Run re-core -c path/to/settings.json
You should see output similar to the following:
$ re-core -c ./examples/settings-example.json
2014-12-10 19:24:02.012102 +0000 - app_component="recore" - source_ip="" - log_level="INFO" - playbook_id="" - deployment_id="" - user_id="" - active_step="" - deploy_phase="" - message="Initialized core logging with level=INFO and log file=/tmp/recore.log"
Additional output will be directed to the log file you configured in the settings.json file. The default log file is called recore.log and will be in your present working directory.
3.2.4. Per-release Logging¶
By default, the FSM will log to the console and a single logfile (LOGFILE).
Optionally, one may log the FSM activity for each release to a separate file. This is done by configuring the re-core RELEASE_LOG_DIR setting with the path to the log-holding directory.
If per-release logging is enabled, the log files will be created as: RELEASE_LOG_DIR/FSM-STATE_ID.log
Warning
Be sure the FSM has permission to write the specified directory. You won’t find out it can’t until the first release is attempted.
1 2 3 4 5 6 7 | {
"LOGFILE": "recore.log",
"RELEASE_LOG_DIR": "/var/log/recore",
"MQ": {
"SERVER": "amqp.example.com"
}
}
|
3.2.5. Pre-Deployment Checks¶
An re-core instance may be configured to run one or more scripts prior to the deployment of any playbook. Each pre-deployment check defines the command to run and the expected result from the command. If expected equals observed, then the check is considered to have passed. If expected is not equal to observed, then the check has failed and the entire deployment is marked as failed.
Important
These checks apply to all deployments
Configuration of pre-deployment checks takes place in the re-core setting.json file.
Example settings
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | {
"LOGFILE": "recore.log",
"RELEASE_LOG_DIR": null,
"PRE_DEPLOY_CHECK": [
{
"NAME": "Require Change Record",
"COMMAND": "servicenow",
"SUBCOMMAND": "getchangerecord",
"PARAMETERS": {
"project": "myproject",
"some_filter": "to find the record"
},
"EXPECTATION": {
"status": "completed",
"data": {
"exists": true
}
}
}
]
}
|
Here we see a new directive, PRE_DEPLOY_CHECK (line 4), this key holds a list whose members are dictionaries (lines 5 → 19). This example has one dictionary. It has several keys, starting with NAME, that is the name of the check, Require Change Record. You can give any name you want as long as it is JSON parsable.
Now let’s look at this nested-dictionary closer:
{
"NAME": "Require Change Record",
"COMMAND": "servicenow",
"SUBCOMMAND": "getchangerecord",
"PARAMETERS": {
"project": "myproject",
"some_filter": "to find the record"
},
"EXPECTATION": {
"status": "completed",
"data": {
"exists": true
}
}
}
- COMMAND - Name of the worker to run the check with, re-worker-servicenow in this example
- SUBCOMMAND - The specific sub-command to run on that worker
- PARAMETERS - Dictionary with variable keys depending on what your worker requires
- EXPECTATION - The result we expected to get back from the check.
Pass or fail is determined by comparing the actual response against EXPECTATION. If they are the same then the check passes. If they differ then the check fails and the deployment is marked as failed and aborted.
3.2.6. Post-Deployment Action¶
Similar in functionality to the pre-deployment check, re-core allows us to run a set of worker steps after each deployment as well. What makes POST_DEPLOY_ACTION different from PRE_DEPLOY_CHECK is that pre-deployment checks allow you to specify expected results, whereas post-deploy actions only check for completed or failed return-statuses.
If a post-deploy action fails (by returning a status other than completed), then the deployment is recorded as a failure.
Important
These actions apply to all deployments
Configuration of pre-deployment checks takes place in the re-core setting.json file.
Let’s take a look at example settings for a post-deploy action which records the time the deployment finished in a Service Now change record.
1 2 3 4 5 6 7 8 9 10 | {
"POST_DEPLOY_ACTION": [
{
"NAME": "Update End Time",
"COMMAND": "servicenow",
"SUBCOMMAND": "UpdateEndTime",
"PARAMETERS": {}
}
]
}
|
In this example we’re defining an empty PARAMETERS key. This is because the ServiceNow worker’s UpdateEndTime sub-command only requires dynamic arguments. The FSM (re-core) will send dynamic arguments to the worker automatically.
3.2.7. Trigger Steps (Hooks)¶
Triggers Steps (or hooks in some parlance) automatically add steps into a deployment based on pre-defined WHEN conditions:
- NEXT_COMMAND - Trigger added when the next command matches the value
- NEXT_SUBCOMMAND - Trigger added when the next subcommand matches the value
A trigger step is added into a deployment only when all the defined criteria match. When multiple WHEN conditions are present, the WHEN expression is treated as a boolean AND statement.
Step triggers are defined outside of the main settings file. Set the value of the TRIGGERS parameter to the path of your triggers file. An example triggers file is included in the re-core source distribution: examples/triggers/triggers.trigger.json.
Syntax for defining triggers follows the following pattern:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | {
"STEP_TRIGGERS": [
{
"DESCRIPTION": "Sleep for a second before running any httprequest subcommands",
"WHEN": {
"NEXT_COMMAND": "httprequest"
},
"COMMAND": "sleep",
"SUBCOMMAND": "seconds",
"PARAMETERS": {
"seconds": 1
}
}
]
}
|
In the previous example, if our deployment had any httprequest steps defined then a sleep:seconds step with parameters {'seconds': 1} would be inserted before each httprequest step.
If we wanted to trigger on a specific subcommand from the httprequest worker we would add another condition to the WHEN expression:
1 2 3 4 5 6 | {
"WHEN": {
"NEXT_COMMAND": "httprequest",
"NEXT_SUBCOMMAND": "Get"
}
}
|
Multiple triggers may be defined. Triggers are applied in order:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | {
"STEP_TRIGGERS": [
{
"DESCRIPTION": "Sleep for a sec before bigip",
"WHEN": {
"NEXT_COMMAND": "bigip",
},
"COMMAND": "sleep",
"SUBCOMMAND": "seconds",
"PARAMETERS": {
"seconds": 1
}
},
{
"DESCRIPTION": "Run a noop before we sleep",
"WHEN": {
"NEXT_COMMAND": "sleep",
},
"COMMAND": "noop",
"SUBCOMMAND": "Whatever",
"PARAMETERS": {}
}
]
}
|
3.2.8. RE-CORE Disconnection¶
Much like the worker component re-core will attempt to reconnect to the bus if it gets disconnected. However, a disconnect of re-core is likely to be disruptive due to the use of temporary queues. Do not expect a flaky re-core connection to be sufficient. A disconnection of re-core should always stop a deployment dead in it’s tracks and not restart it if able to reconnect.
Warning
If a deployment is taking place while re-core is disconnected it’s highly unlikely that a notification will be sent out showing a failure.