|
| 1 | +--- |
| 2 | +title: Adding a field to the API |
| 3 | +layout: default |
| 4 | +--- |
| 5 | +This page describes how to add a field to XenAPI. |
| 6 | + |
| 7 | +Bumping the database schema version |
| 8 | +----------------------------------- |
| 9 | +Whenever a field is added to or removed from the API, its schema version needs |
| 10 | +to be increased. XAPI needs this fundamental procedure in order to be able to |
| 11 | +detect that an automatic database upgrade is necessary, or to find out that the |
| 12 | +new schema is incompatible with the existing database. If the schema version is |
| 13 | +not bumped, XAPI will start failing in unpredictable ways. Note that bumping |
| 14 | +the version is not necessary when adding functions, only when adding fields. |
| 15 | + |
| 16 | +The current version number is kept at the top of the file |
| 17 | +`ocaml/idl/datamodel.ml` in the variables `schema_major_vsn` and |
| 18 | +`schema_minor_vsn`, of which only the latter should be incremented (the major |
| 19 | +version only exists for historical reasons). When moving to a new XenServer |
| 20 | +release, also update the variable `last_release_schema_minor_vsn` to the schema |
| 21 | +version of the last release. To keep track of the schema versions of recent |
| 22 | +XenServer releases, the file contains variables for these, such as |
| 23 | +`miami_release_schema_minor_vsn`. After starting a new version of Xapi on an |
| 24 | +existing server, the database is automatically upgraded if the schema version |
| 25 | +of the existing database matches the value of `last_release_schema_*_vsn` in the |
| 26 | +new Xapi. |
| 27 | + |
| 28 | +As an example, the patch below shows how the schema version was bumped when the |
| 29 | +new API fields used for ActiveDirectory integration were added: |
| 30 | + |
| 31 | + --- a/ocaml/idl/datamodel.ml Tue Nov 11 16:17:48 2008 +0000 |
| 32 | + +++ b/ocaml/idl/datamodel.ml Tue Nov 11 15:53:29 2008 +0000 |
| 33 | + @@ -15,17 +15,20 @@ open Datamodel_types |
| 34 | + open Datamodel_types |
| 35 | + |
| 36 | + (* IMPORTANT: Please bump schema vsn if you change/add/remove a _field_. |
| 37 | + You do not have to dump vsn if you change/add/remove a message *) |
| 38 | + |
| 39 | + let schema_major_vsn = 5 |
| 40 | + -let schema_minor_vsn = 55 |
| 41 | + +let schema_minor_vsn = 56 |
| 42 | + |
| 43 | + (* Historical schema versions just in case this is useful later *) |
| 44 | + let rio_schema_major_vsn = 5 |
| 45 | + let rio_schema_minor_vsn = 19 |
| 46 | + |
| 47 | + +let miami_release_schema_major_vsn = 5 |
| 48 | + +let miami_release_schema_minor_vsn = 35 |
| 49 | + + |
| 50 | + (* the schema vsn of the last release: used to determine whether we can |
| 51 | + upgrade or not.. *) |
| 52 | + let last_release_schema_major_vsn = 5 |
| 53 | + -let last_release_schema_minor_vsn = 35 |
| 54 | + +let last_release_schema_minor_vsn = 55 |
| 55 | + |
| 56 | +Adding the new field to some existing class |
| 57 | +------------------------------------------- |
| 58 | +## ocaml/idl/datamodel.ml |
| 59 | +Add new "field" line the class in idl/datamodel.ml. The new field might require |
| 60 | +a suitable default value. This default value is used in case the user does not |
| 61 | +provide a value for the field. |
| 62 | + |
| 63 | +A field has a number of parameters: |
| 64 | + |
| 65 | +- The lifecycle parameter, which shows how the field has evolved over time. |
| 66 | +- The qualifier parameter, which controls access to the field. The following |
| 67 | + values are possible: |
| 68 | + |
| 69 | +| Values | Meaning | |
| 70 | +| --------- | --------------------------------------------- | |
| 71 | +| StaticRO | Field is set statically at install-time. | |
| 72 | +| DynamicRO | Field is computed dynamically from the guest. | |
| 73 | +| RW | Field is read/write. | |
| 74 | + |
| 75 | +- The ty parameter for the type of the field. |
| 76 | +- The default_value parameter. |
| 77 | +- The name of the field. |
| 78 | +- A documentation string. |
| 79 | + |
| 80 | +Example of a field in the pool class: |
| 81 | + |
| 82 | + field ~lifecycle:[Published, rel_orlando, "Controls whether HA is enabled"] |
| 83 | + ~qualifier:DynamicRO ~ty:Bool |
| 84 | + ~default_value:(Some (VBool false)) "ha_enabled" "true if HA is enabled on the pool, false otherwise"; |
| 85 | + |
| 86 | +See datamodel_types.ml for information about other parameters. |
| 87 | + |
| 88 | +Adding a field would change the constructors for the class – functions |
| 89 | +Db.*.create – and therefore, any references to these in the code need to be |
| 90 | +updated. In the example, the argument ~ha_enabled:false should be added to any |
| 91 | +call to Db.Pool.create. |
| 92 | + |
| 93 | +## ocaml/client_records/records.ml |
| 94 | +If you want this field to show up in the CLI (which you probably do), you will |
| 95 | +also need to modify the Records module, in the file |
| 96 | +`ocaml/client_records/records.ml`. Find the record function for the class which |
| 97 | +you have modified, add a new entry to the fields list using make_field, which |
| 98 | +has the type: |
| 99 | + |
| 100 | + Type: ?add_to_set:(string -> unit) -> |
| 101 | + ?remove_from_set:(string -> unit) -> |
| 102 | + ?add_to_map:(string -> string -> unit) -> |
| 103 | + ?remove_from_map:(string -> unit) -> |
| 104 | + ?set_in_map:(string -> string -> unit) -> |
| 105 | + ?set:(string -> unit) -> |
| 106 | + ?get_set:(unit -> string list) -> |
| 107 | + ?get_map:(unit -> (string * string) list) -> |
| 108 | + ?expensive:bool -> |
| 109 | + ?hidden:bool -> |
| 110 | + ?deprecated:bool -> |
| 111 | + ?case_insensitive:bool -> |
| 112 | + name:string -> |
| 113 | + get:(unit -> string) -> |
| 114 | + unit -> field |
| 115 | + |
| 116 | +The only required parameters are name and get (and unit, of course ). |
| 117 | +If your field is a map or set, then you will need to pass in get_{map,set}, and |
| 118 | +optionally set_{map,set}, if it is a RW field. The hidden parameter is useful |
| 119 | +if you don't want this field to show up in a *_params_list call. As an example, |
| 120 | +here is a field that we've just added to the SM class: |
| 121 | + |
| 122 | + make_field ~name:"versioned-capabilities" |
| 123 | + ~get:(fun () -> Record_util.s2sm_to_string "; " (x ()).API.sM_versioned_capabilities) |
| 124 | + ~get_map:(fun () -> (x ()).API.sM_versioned_capabilities) |
| 125 | + ~hidden:true (); |
| 126 | + |
| 127 | +Testing |
| 128 | +------- |
| 129 | +The new fields can be tested by copying the newly compiled xapi binary to a |
| 130 | +test box. After the new xapi service is started, the file |
| 131 | +*/var/log/xensource.log* in the test box should contain a few lines reporting the |
| 132 | +successful upgrade of the metadata schema in the test box: |
| 133 | + |
| 134 | + [...|xapi] Db has schema major_vsn=5, minor_vsn=57 (current is 5 58) (last is 5 57) |
| 135 | + [...|xapi] Database schema version is that of last release: attempting upgrade |
| 136 | + [...|sql] attempting to restore database from /var/xapi/state.db |
| 137 | + [...|sql] finished parsing xml |
| 138 | + [...|sql] writing db as xml to file '/var/xapi/state.db'. |
| 139 | + [...|xapi] Database upgrade complete, restarting to use new db |
| 140 | + |
| 141 | +Making this field accessible as a CLI attribute |
| 142 | +----------------------------------------------- |
| 143 | +XenAPI functions to get and set the value of the new field are generated |
| 144 | +automatically. It requires some extra work, however, to enable such operations |
| 145 | +in the CLI. |
| 146 | + |
| 147 | +The CLI has commands such as host-param-list and host-param-get. To make a new |
| 148 | +field accessible by these command, the file client_records/records.ml needs to |
| 149 | +be edited. For the pool.ha-enabled field, the pool_record function in this file |
| 150 | +contains the following (note the convention to replace underscores by hyphens |
| 151 | +in the CLI): |
| 152 | + |
| 153 | + let pool_record rpc session_id pool = |
| 154 | + ... |
| 155 | + [ |
| 156 | + ... |
| 157 | + make_field ~name:"ha-enabled" ~get:(fun () -> string_of_bool (x ()).API.pool_ha_enabled) (); |
| 158 | + ... |
| 159 | + ]} |
| 160 | + |
| 161 | +See records.ml for examples of handling field types other than Bool. |
0 commit comments