Skip to content

Commands

Command is a core entity used to execute various actions in Cetmix Tower. Depending on the action selected, it can be executed on a remote server or locally on the Cetmix Tower server.

Access Rules

Group Action Condition
User R Access level is "User" and user is added in "Users"
User R Access level is "User" and user is added in "Users" in related Servers
Manager R Access level is "Manager" or less and record is not connected to any Server
Manager R Access level is "Manager" or less and user is added in "Users" or "Managers"
Manager R Access level is "Manager" or less and user is added in "Users" or "Managers" in related Servers
Manager CRU Access level is "Manager" or less and user is added in "Managers"
Manager CRUD Access level is "Manager" or less and record is created by user
Root CRUD Any record

Info

CRUD stands for Create, Read, Update, Delete

Command Configuration

Commands are located under the Cetmix Tower > Commands > Commands menu.

Command List

Fields

Command Form

Important

Form view may differ based on the current user Access Level.

Field Description
Name Command readable name.
Reference Used for Odoo automation and YAML export/import. Leave blank to generate it automatically.
Action Action executed by the Command.
File Template File template that will be used to create or update file. Check File Templates for more details.
Default Path Specify path where Command will be executed. This field supports Variables.
Allow Parallel Run If disabled, only one copy of this Command can be run on the same server at the same time. Otherwise, the same Command can be run in parallel.
No Split for sudo If enabled, commands containing && will not be split into multiple segments when executed with sudo with password.
Note Comments or user notes.
Servers List of Servers this Command can be run on. Leave this field blank to make the Command available to all servers.
OSes List of operating systems this Command is available. Leave this field blank to make the Command available for all OSes.
Tags Make usage as search more convenient
Access Level Minimum access level required to run this Command.
Server Status Server Status upon successful Command execution. Leave Undefined to keep status unchanged.
Variables Variables used in this Command.

Warning

Ensure ssh user has access to the location where Command is executed even when executing Command using sudo.

Warning

Variables used in Command are rendered in different modes based on the Command action.

Notebook Tabs

Tab Description
Code Code to execute. Can be an SSH command or Python code based on selected action. This field supports Variables.
Access Access Roles for this record for specific users.
YAML YAML code of the Command. This tab is visible only to users with "Cetmix Tower YAML > Export" setting enabled.

Command Actions

The following actions are available (selection key in parentheses for YAML):

Action Description
SSH command (ssh_command) Execute a shell command using ssh connection on remote server.
Run Python code (python_code) Execute Python code on the Tower server. See Python Code Commands.
Create file using template (file_using_template) Create or update a file using the selected file template and push/pull it to the remote server or tower. If the file already exists, it will be overwritten. Important: only available inside Flight Plans.
Run flight plan (plan) Run a Flight Plan from the Command. Important: only available inside Flight Plans.
Trigger jet action (jet_action) Run a Jet action (e.g. start, stop, create). Requires selecting a Jet action in the Command.

SSH Commands

SSH commands are used to execute a shell command using ssh connection on remote server. Here are some best practices you should follow:

Use simple commands

Try to avoid using && or ; joined commands unless this is really needed. Use flight plans instead.

Why?

  • Simple commands are easier to reuse across multiple Flight Plans.
  • When a joined command is run using sudo with password, it is split and commands are executed one by one. This behavior can be changed by using the No Split for sudo option.

Example

Not recommended:

apt-get update && apt-get upgrade -y && apt-get install doge-meme-generator

Way to go:

apt-get update
apt-get upgrade -y
apt-get install doge-meme-generator

Do not change directory using shell commands

Do not use cd or chdir commands. Use Default Path field in Command or Path field in Flight Plan line.

Why?

  • Tower will automatically adjust the command to ensure it is properly executed in the specified location.

Example

Not recommended:

cd /home/{{ tower.server.username }}/memes && cat my_doge_memes.txt

Way to go:

  • Add the following value in the Default Path command field or Path field of a flight plan line:
/home/{{ tower.server.username }}/memes
  • Leave the command code as follows:
cat my_doge_memes.txt

Python Code Commands

Python commands are used to execute Python code on the Tower server. They provide seamless integration with Odoo and allow you to use Python to automate and extend Cetmix Tower. By their nature they are similar to Odoo Automated Actions.
Python commands can use the following variables exposed to the code:

Variable Description
Odoo / Tower objects
uid Current Odoo user ID (integer).
user Current Odoo user record.
env Odoo environment on which the action is triggered.
server Server on which the command is run (or None if not server context).
jet_template Jet Template for this run (or None).
jet Jet for this run (or None).
waypoint Jet waypoint for this run (or None).
tower cetmix.tower helper (run commands, flight plans, get/set variables, etc.).
tower_servers Shortcut to env['cx.tower.server'].
tower_jets Shortcut to env['cx.tower.jet'].
tower_commands Shortcut to env['cx.tower.command'].
tower_plans Shortcut to env['cx.tower.plan'].
tower_waypoints Shortcut to env['cx.tower.jet.waypoint'].
Python libraries
re Python re (regex).
time, datetime, dateutil, timezone Time-related libraries (as exposed by safe_eval).
requests Python requests. Methods: post, get, delete, request.
urllib_parse Python urllib.parse.
json Python json. Methods include dumps.
hashlib Python hashlib (e.g. sha1, sha256, md5, new).
hmac Python hmac (e.g. new, compare_digest).
tldextract tldextract (e.g. tldextract.extract() for domain parsing).
dns dnspython (e.g. dns.resolver, dns.reversename, dns.exception).
Odoo helpers
float_compare Odoo helper to compare floats with given precision.
UserError Odoo exception to raise for user-facing errors.

To return a result from Python, assign an exit code and message to the result variable (of type dict) as follows:

Info

# Success
result = {
    "exit_code": 0,
    "message": "This will be logged as a result message because exit code == 0",
}

# Error
result = {
    "exit_code": 21,
    "message": "This will be logged as an error message because exit code != 0",
}

exit_code value will be used as a Command result status. message will be logged as a result message if exit_code is 0 or an error message if exit_code is not 0.

Example

Python command that creates a new instance in the Hetzer Cloud using API

# API Token
api_token = #!cxtower.secret.hetzner_api_token!#

# Set the required headers
headers = {
    'Authorization': 'Bearer '+ api_token,
    'Content-Type': 'application/json'
}

# API URL to create a server
url = "https://api.hetzner.cloud/v1/servers"

# Define the payload with server properties
data = {
    "name": {{ tower.server.reference }}.replace("_", "-"),  # Hetzner doesn't support '_' in names
    "server_type": {{ hetzner_server_type }}.lower(),       # CX22 -> cx22
    "image": {{ hetzner_os_image }},                        # Ubuntu 24.04 image
    "location": {{ hetzner_location }}.lower(),             # NBG1-> nbg1 Nuremberg location (nbg1)
    "public_net": {
        "enable_ipv4": True   # Enable IPv4 (request for a new one)
    },
    "ssh_keys": [server.ssh_key_id.reference and server.ssh_key_id.reference.replace("_", "-")]
}

# Make the request to create the server
response = requests.post(url, headers=headers, data=json.dumps(data))

# Parse and log the response
if response.status_code in [200, 201]:
exit_code = 0
result = response.json()

# Set server ipv4 address and password
ip_v4_address = result['server']['public_net']['ipv4']['ip']
root_password = result['root_password']
server.write({
    "ip_v4_address": ip_v4_address,
    "ssh_password": root_password
    })

# Save Hetzner server id in variable
server_reference = server.reference
variable_reference = "hetzner_server_id"
hetzner_server_id = result['server']['id']
tower.server_set_variable_value(server_reference, variable_reference, hetzner_server_id)

else:
exit_code = response.status_code
result = response.text

result = {
    "exit_code": exit_code,
    "message": response.json(),
}

YAML Format Specification

cetmix_tower_model: command
access_level: manager  # Access level required to run the command. Available options: user, manager, root
reference: check_ssh_connection  # Reference of the command
name: Check SSH connection  # Name of the command
action: python_code  # Action to execute. Available options: ssh_command, python_code, file_using_template, plan, jet_action
allow_parallel_run: false  # Allow parallel run, Boolean
note: Check if SSH connection is available  # Note of the command
os_ids:  # List of Operating System references or an Operating System object. Operating Systems on which the command can be run.
- ubuntu_24_04  # Operating System reference or an Operating System object
- debian_12  # Operating System reference or an Operating System object
tag_ids:  # List of Tag references or a Tag object. Command tags.
- system  # Tag reference or a Tag object
path: false  # Default path to execute the command
file_template_id: custom_template  # File Template reference or a File Template object. Used only for the 'file_using_template' action
flight_plan_id: build_odoo_base_image_if_not_exists  # Flight Plan reference or a Flight Plan object. Used only for the 'plan' action
jet_action_id: my_jet_action  # Jet Action reference or a Jet Action object. Used only for the 'jet_action' action
code: |
aws_status = aws_check_status(aws_access_key=#!cxtower.secret.aws_access_key!#)
if {{ odoo_version }} == "16.0":
    result = tower.server_check_ssh_connection(server_reference={{ tower.server.reference }})
else:
    result = {
    "exit_code": 1,
    "message": "SSH connection is not available for Odoo version {{ odoo_version }} and db {{ odoo_db_name }}",
    }
server_status: running  # Server status to set after the command execution. Available options: stopped, starting, running, stopping, restarting, deleting, delete_error. Leave empty to keep status unchanged
variable_ids: # List of Variable references or Variable objects. Variables used in the command.
- odoo_version # Variable reference or a Variable object
- odoo_db_name # Variable reference or a Variable object
secret_ids: # List of Secret references or Secret objects. Secrets used in the command.
- aws_access_key # Secret reference or a Secret object

Please refer to the General YAML Format Specification for more details.