diff --git a/source/_static/images/error-message-hindi-locale.png b/source/_static/images/error-message-hindi-locale.png new file mode 100644 index 0000000000..4ae5b10ba1 Binary files /dev/null and b/source/_static/images/error-message-hindi-locale.png differ diff --git a/source/adminguide/error_messages.rst b/source/adminguide/error_messages.rst new file mode 100644 index 0000000000..3a40dea981 --- /dev/null +++ b/source/adminguide/error_messages.rst @@ -0,0 +1,220 @@ +.. Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information# + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + + +Customizing API Error Messages +=============================== + +Many API errors returned by CloudStack are generated from a set of message +templates rather than hard-coded strings. This lets operators reword, +retranslate, or add detail to error messages without changing or recompiling +any code, and lets a message reveal more detail to a root admin than to a +regular user. + +Where the templates live +------------------------- + +Message templates are stored in a JSON file on each management server: + +:: + + /etc/cloudstack/management/messages/error-messages.json + +This file is installed as a configuration file and is not overwritten during +upgrades. Each entry maps an error key to a message template, for example: + +.. code:: json + + { + "vm.deploy.template.not.found": "The template used to deploy this instance could not be found.", + "vm.stop.vm.not.found": "Instance {{instance}} could not be found." + } + +A template may reference values from the error's metadata using +``{{placeholder}}`` syntax. Available placeholders depend on the specific +error and are filled in from information CloudStack already has about the +failure (for example the instance, volume, or network involved). + +Editing a message and saving the file takes effect immediately on that +management server: **no restart is required**. Each management server +reloads the file when it detects a change. + +Admin-only variants +-------------------- + +Any key may have an admin-only counterpart, defined by appending ``.admin`` +to the key name: + +.. code:: json + + { + "vm.stop.vm.not.found": "The instance could not be found.", + "vm.stop.vm.not.found.admin": "Instance {{instance}} (ID: {{instanceId}}) could not be found." + } + +When a root admin triggers the error, the ``.admin`` variant is used if one +is defined; everyone else, and any key with no ``.admin`` variant, falls back +to the base key. This lets an admin see more identifying detail (such as an +internal database ID) without exposing it to regular users. + +Adding plugin or operator override files +------------------------------------------ + +In addition to editing ``error-messages.json`` directly, an operator (or a +plugin's installer) may drop extra override files into the same +``messages/`` directory: + +:: + + /etc/cloudstack/management/messages/error-messages-.json + +The ```` is any name you choose, conventionally the name of the +plugin or customization it belongs to (for example +``error-messages-mycompany.json``). These files are **not** shipped inside +any CloudStack package or plugin JAR; they are purely a runtime mechanism, +so you create them yourself on each management server. + +An override file only needs to contain the keys it changes: + +.. code:: json + + { + "vm.stop.vm.not.found": "Custom wording for this one message only." + } + +All matching ``error-messages-*.json`` files in the directory are merged on +top of the main ``error-messages.json``, in alphabetical order by filename, +with later files taking precedence on a per-key basis. If two override files +define the same key, the alphabetically later filename wins and a warning is +logged. The merge happens key by key, not file by file, overriding a base +key leaves that key's ``.admin`` variant (if defined elsewhere) untouched. + +Like the main file, override files are hot-reloaded - adding, removing, or +editing one takes effect on the next request, with no restart. + +Multi-management-server deployments +-------------------------------------- + +Each management server reloads based only on its own local copy of these +files. In a deployment with more than one management server, keep +``error-messages.json`` and any override files in sync across every node, +for example by managing them with the same configuration-management tooling +used for the rest of the management server configuration. A change made on +only one node will only be visible to API calls handled by that node. + +Global settings for metadata rendering +------------------------------------------ + +Two global settings control how object values (such as a VM or volume) are +rendered when substituted into a message template: + +.. cssclass:: table-striped table-bordered table-hover + ++------------------------------------------------------+-------------------------------------------------------------------+ +| Global Setting | Description | ++======================================================+===================================================================+ +| ``error.message.metadata.prefer.tostring`` | When ``true``, prefer the object's own ``toString()`` over the | +| | default display-name lookup when rendering it into a message. | +| | Default: ``false``. | ++------------------------------------------------------+-------------------------------------------------------------------+ +| ``error.message.metadata.include.id.for.admins`` | When ``true``, include the internal database ID (in addition to | +| | the UUID) for objects referenced in a message shown to a root | +| | admin. Default: ``true``. | ++------------------------------------------------------+-------------------------------------------------------------------+ + +Both settings require a **management server restart** to take effect. This +is deliberate, unlike most dynamic global settings, these are read on every +error message rendered, so making them dynamic would add avoidable database +load on a busy system. + +Structured fields in the API response +----------------------------------------- + +Alongside the existing ``errortext`` field, API error responses (and failed +async job results) also include: + +- ``errortextkey``: the stable error key (for example + ``vm.stop.vm.not.found``), unaffected by any customization of the message + text itself. +- ``errormetadata``: the raw metadata values used to fill in the message + template, as a key/value map. + +These are useful for API clients and integrations that want to react to a +specific error condition or localize the message themselves, rather than +matching against the (customizable) human-readable ``errortext`` string. + +For example, a failed ``deployVirtualMachine`` call that hits an account +resource limit returns: + +.. code:: json + + { + "deployvirtualmachineresponse": { + "uuidList": [], + "errorcode": 535, + "cserrorcode": 9999, + "errortext": "Unable to deploy Instance because allocating 1 more Instance would exceed the Account limits. Current: 2, Reserved: 0, Limit: 2. Release unused resources, then retry.", + "errortextkey": "vm.deploy.resourcelimit.exceeded.account", + "errormetadata": { + "resourceRequested": "1", + "resourceTypeDisplay": "Instance", + "resourceOwnerType": "Account", + "resourceAmount": "2", + "resourceReserved": "0", + "resourceLimit": "2" + } + } + } + +``errortextkey`` and the keys inside ``errormetadata`` stay the same no +matter how ``error-messages.json`` is customized; only ``errortext`` changes +with the template. + +Localizing messages in the UI +--------------------------------- + +``error-messages.json`` controls the message returned by the API itself, but +the UI has its own, separate localization mechanism based on the same +``errortextkey``. The UI's locale files, one JSON file per language under +``ui/public/locales/`` (for example ``hi.json`` for Hindi, ``fr_FR.json`` for +French), are flat key/value maps of translation strings, already used for +every other piece of UI text. + +If the current locale's file has an entry whose key exactly matches an +error's ``errortextkey``, the UI shows that translation instead of the +server-rendered ``errortext``, substituting ``{{placeholder}}`` tokens in it +with the matching values from ``errormetadata``. If no matching key exists in +the current locale, the UI falls back to the server's ``errortext`` as-is. + +This means a developer or operator can add or edit a UI-side translation for +a specific error message by adding a key equal to its ``errortextkey`` to the +relevant locale file, with no change needed on the management server. + +**Admin variant**: like the server, before falling back to the base key, the +UI first tries a key suffixed ``.admin`` when the current user is a root +admin, the same ``.admin`` suffix and root-admin-only condition described +under "Admin-only variants" above. There is no equivalent variant for +resource admins, domain admins, or regular users. + +For example, a translation added to ``ui/public/locales/hi.json`` for the +``vm.deploy.resourcelimit.exceeded.account`` error from the example above +would show a Hindi-locale user: + +.. figure:: /_static/images/error-message-hindi-locale.png + :align: center + :alt: The same resource-limit error rendered in Hindi via a UI locale file + + The account resource-limit error from the example above, localized in + the UI via a ``hi.json`` entry keyed on ``errortextkey``. diff --git a/source/adminguide/index.rst b/source/adminguide/index.rst index ada0a37b4d..3f2017e856 100644 --- a/source/adminguide/index.rst +++ b/source/adminguide/index.rst @@ -163,6 +163,7 @@ Managing the Cloud management kms + error_messages System Reliability and Availability -----------------------------------