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.
Fields
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 orPath
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(),
}