|
| 1 | +Writing Extensions for CloudStack |
| 2 | +================================= |
| 3 | + |
| 4 | +The CloudStack Extensions Framework allows developers and operators to write extensions using any programming language or script. From CloudStack’s perspective, an extension is simply an executable capable of handling specific actions and processing input payloads. CloudStack invokes the executable by passing the action name and the path to a JSON-formatted payload file as command-line arguments. The extension processes the payload, performs the required operations on an external system, and returns the result as a JSON response written to `stdout`. |
| 5 | + |
| 6 | + |
| 7 | +Create a New Extension |
| 8 | +^^^^^^^^^^^^^^^^^^^^^^ |
| 9 | + |
| 10 | +You must first register a new extension using the API or UI: |
| 11 | + |
| 12 | +.. code-block:: bash |
| 13 | +
|
| 14 | + cloudmonkey createExtension name=myext path=myext-executable |
| 15 | +
|
| 16 | +Arguments: |
| 17 | + |
| 18 | +- ``name``: Unique name |
| 19 | +- ``path``: Relative path to the executable. Root path will be `/usr/share/cloudstack-management/extensions/<extension_name>` |
| 20 | + |
| 21 | +The path must be: |
| 22 | + |
| 23 | +- Executable (``chmod +x``) |
| 24 | +- Owned by the ``cloud:cloud`` user |
| 25 | +- Present on all management servers (identical path and binary) |
| 26 | + |
| 27 | +If no explicit path is provided during extension creation, CloudStack will scaffold a basic shell script at a default location with minimal required action handlers. This provides a starting point for customization and ensures the extension is immediately recognized and callable by the system. |
| 28 | + |
| 29 | +CloudStack checks extension readiness periodically and shows its state in the UI/API. |
| 30 | + |
| 31 | +Extension Structure |
| 32 | +^^^^^^^^^^^^^^^^^^^ |
| 33 | + |
| 34 | +Your extension must support the following invocation structure: |
| 35 | + |
| 36 | +.. code-block:: bash |
| 37 | +
|
| 38 | + /path/to/executable <action> <payload_file> <timeout_seconds> |
| 39 | +
|
| 40 | +Arguments: |
| 41 | + |
| 42 | +- ``<action>``: Action name (e.g., ``deploy``, ``start``, ``status``) |
| 43 | +- ``<payload_file>``: Path to the input JSON file |
| 44 | +- ``<timeout_seconds>``: Max duration CloudStack will wait for completion |
| 45 | + |
| 46 | +Sample Invocation: |
| 47 | + |
| 48 | +.. code-block:: bash |
| 49 | +
|
| 50 | + /usr/share/cloudstack-management/extensions/myext/myext.py /var/lib/cloudstack/management/extensions/myext/162345.json 60 |
| 51 | +
|
| 52 | +Input Format (Payload) |
| 53 | +^^^^^^^^^^^^^^^^^^^^^^ |
| 54 | + |
| 55 | +CloudStack provides input via a JSON file, which your executable must read and parse. |
| 56 | + |
| 57 | +Example: |
| 58 | + |
| 59 | +.. code-block:: json |
| 60 | +
|
| 61 | + { |
| 62 | + "resourceType": "VM", |
| 63 | + "resourceUuid": "2b3c3e54-1ef3-4b8b-941d-61a1adcc7fa2", |
| 64 | + "action": "deploy", |
| 65 | + "accessDetails": { |
| 66 | + "username": "admin", |
| 67 | + "apiKey": "ABCD1234" |
| 68 | + } |
| 69 | + } |
| 70 | +
|
| 71 | +The schema varies depending on the resource and action. Use this to perform context-specific logic. |
| 72 | + |
| 73 | +Output Format |
| 74 | +^^^^^^^^^^^^^ |
| 75 | + |
| 76 | +Your extension should write a response JSON to ``stdout``. Example: |
| 77 | + |
| 78 | +.. code-block:: json |
| 79 | +
|
| 80 | + { |
| 81 | + "status": "success", |
| 82 | + "message": "Deployment completed" |
| 83 | + } |
| 84 | +
|
| 85 | +For custom actions, CloudStack may use the response to show it in the UI. |
| 86 | + |
| 87 | +Action Lifecycle |
| 88 | +^^^^^^^^^^^^^^^^ |
| 89 | + |
| 90 | +1. A CloudStack action (e.g., deploy VM) triggers a corresponding extension action. |
| 91 | +2. CloudStack invokes the extension’s executable with appropriate parameters. |
| 92 | +3. The extension processes the input and responds within the timeout. |
| 93 | +4. CloudStack continues orchestration based on the result. |
| 94 | + |
| 95 | +Custom Actions |
| 96 | +^^^^^^^^^^^^^^ |
| 97 | + |
| 98 | +You can define new custom actions for users or admin-triggered workflows. |
| 99 | + |
| 100 | +- Register via UI or ``addCustomAction`` API |
| 101 | +- Define input parameters (name, type, required) |
| 102 | +- Implement the handler for the custom action in your executable. |
| 103 | + |
| 104 | +CloudStack UI will render forms dynamically based on these definitions. |
| 105 | + |
| 106 | +Best Practices |
| 107 | +^^^^^^^^^^^^^^ |
| 108 | + |
| 109 | +- Make executable/script idempotent and stateless |
| 110 | +- Validate all inputs before acting |
| 111 | +- Avoid hard dependencies on CloudStack internals |
| 112 | +- Implement logging for troubleshooting |
| 113 | +- Use exit code and ``stdout`` for signaling success/failure |
| 114 | + |
| 115 | +Extension Examples |
| 116 | +^^^^^^^^^^^^^^^^^^ |
| 117 | + |
| 118 | +**Bash Example** |
| 119 | + |
| 120 | +.. code-block:: bash |
| 121 | +
|
| 122 | + #!/bin/bash |
| 123 | + ACTION=$1 |
| 124 | + FILE=$2 |
| 125 | + TIMEOUT=$3 |
| 126 | +
|
| 127 | + if [ "$ACTION" == "deploy" ]; then |
| 128 | + echo '{ "success": true, "result": { "message": "OK" } }' |
| 129 | + else |
| 130 | + echo '{ "success": false, "result": { "message": "Unsupported action" } }' |
| 131 | + fi |
| 132 | +
|
| 133 | +**Python Example** |
| 134 | + |
| 135 | +.. code-block:: python |
| 136 | +
|
| 137 | + import sys, json |
| 138 | +
|
| 139 | + action = sys.argv[1] |
| 140 | + payload_file = sys.argv[2] |
| 141 | +
|
| 142 | + with open(payload_file) as f: |
| 143 | + data = json.load(f) |
| 144 | +
|
| 145 | + if action == "deploy": |
| 146 | + print(json.dumps({"success": True, "result": {"message": "Deployed"}})) |
| 147 | + else: |
| 148 | + print(json.dumps({"success": False, "result": {"message": "Unknown action"}})) |
| 149 | +
|
| 150 | +For a clearer understanding of how to implement an extension, developers can refer to the base shell script scaffolded by CloudStack for orchestrator-type extensions. This script is located at: |
| 151 | + |
| 152 | +/usr/share/cloudstack-common/scripts/vm/hypervisor/external/provisioner/provisioner.sh |
| 153 | + |
| 154 | +It serves as a template with minimal required action handlers, making it a useful starting point for building new extensions. |
| 155 | + |
| 156 | +Additionally, CloudStack includes built-in extensions for Proxmox and Hyper-V that demonstrate how to implement extensions in different languages - Bash and Python. |
0 commit comments