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.

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

Command List

Fields

Command Form

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

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.
YAML YAML code of the Command. This tab is visible only to users with "Cetmix Tower YAML > Export" setting enabled.

Command Actions

Action Description
SSH command Execute a shell command using ssh connection on remote server.
Execute Python code Execute a Python code on the Tower Server. Check Python Code Commands for more details.
Create file using template Create or update a file using selected file template and push/pull it to remote server/tower. If the file already exists on server, it will be overwritten. Important: this action can be used only in Flight Plans.
Run flight plan Run a Flight Plan from Command. Important: this action can be used only in Flight Plans.

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.

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 a Python code on the Tower Server. The provide seamless integration with Odoo and allow to use the power of Python to automate and extend the Cetmix Tower functionality. By their nature they are similar to Odoo Automated Actions. Python commands can use the following Odoo objects which are exposed to the Python code as variables:

Variable Description
user Current Odoo
env Odoo Environment on which the action is triggered
server Server on which the command is run
tower 'cetmix.tower' helper class
time, datetime, dateutil, timezone Useful Python libraries
requests Python 'requests' library. Available methods: 'post', 'get', 'request'
json Python 'json' library. Available methods: 'dumps'
hashlib Python 'hashlib' library. Available methods: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', 'shake_128', 'shake_256', 'blake2b', 'blake2s', 'md5', 'new'
hmac Python 'hmac' library. Use 'new' to create HMAC objects. Available methods on the HMAC object: 'update', 'copy', 'digest', 'hexdigest'. Module-level function: 'compare_digest'.
float_compare Odoo function to compare floats based on specific precisions
UserError Warning Exception to use with raise

To return result from Python assign exit code and message to the COMMAND_RESULT variable of type dict like this:

Info

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

# Error
COMMAND_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

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