datapath

The Datapath plugin takes a URI which points to virtual disk data and chooses a Xen datapath implementation: driver domain, blkback implementation and caching strategy.

type debug_info = string

Debug context from the caller

type domain = string

A string representing a Xen domain on the local host. The string is guaranteed to be unique per-domain but it is not guaranteed to take any particular form. It may (for example) be a Xen domain id, a Xen VM uuid or a Xenstore path or anything else chosen by the toolstack. Implementations should not assume the string has any meaning.

type uri = string

A URI representing the means for accessing the volume data. The interpretation of the URI is specific to the implementation. Xapi will choose which implementation to use based on the URI scheme.

type implementation = variant { ... }

The choice of blkback to use.

Constructors:

Name Type Description
Blkback
string
use kernel blkback with the given 'params' key
Tapdisk3
string
use userspace tapdisk3 with the given 'params' key
Qdisk
string
use userspace qemu qdisk with the given 'params' key

type backend = struct { ... }

A description of which Xen block backend to use. The toolstack needs this to setup the shared memory connection to blkfront in the VM.

Members:

Name Type Description
domain_uuid
string
UUID of the domain hosting the backend
implementation
implementation
choice of implementation technology

Datapath

Xapi will call the functions here on VM start/shutdown/suspend/resume/migrate. Every function is idempotent. Every function takes a domain parameter which allows the implementation to track how many domains are currently using the volume.

open

[open uri persistent] is called before a disk is attached to a VM. If persistent is true then care should be taken to persist all writes to the disk. If persistent is false then the implementation should configure a temporary location for writes so they can be thrown away on [close].

Definition
OCaml example
Python example
Name Direction Type Description
dbg in debug_info Debug context from the caller
uri in uri A URI which represents how to access the volume disk data.
persistent in bool True means the disk data is persistent and should be preserved when the datapath is closed i.e. when a VM is shutdown or rebooted. False means the data should be thrown away when the VM is shutdown or rebooted.

Client

(* these directives only needed in a toplevel: *)
#require "xcp-api-client";;
#require "lwt";;
#require "lwt.syntax";;
#require "rpc.unix";;

open S
open Datapath
open Types

module Client = Datapath_client(struct
    include Lwt
    let rpc call = return (Rpc_client.do_rpc ~content_type:`XML ~path:"/" ~host:"127.0.0.1" ~port:80 call) (* TODO: Rpc_client needs to support Lwt *)
end)

let result = Client._open ~dbg:"string" ~uri:"string" ~persistent:true;;

Server

(* this line only needed in a toplevel: *)
#require "xcp-api-client";;

open S
open Datapath

module Datapath_myimplementation = functor(M: M) -> struct
    (* by default every operation will return a 'not implemented' exception *)
    include Datapath_skeleton(M)
    (* ... *)
    let _open x =
        let open Types.Datapath.Open in
        let open Types in
        return (`Ok ())
    (* ... *)
end

Client

        
import xmlrpclib
import xapi
from storage import *

if __name__ == "__main__":
    c = xapi.connect()
    results = c.Datapath.open({ dbg: "string", uri: "string", persistent: True })
    print (repr(results))
        

Server

        
import xmlrpclib
import xapi
from storage import *

class Datapath_myimplementation(Datapath_skeleton):
    # by default each method will return a Not_implemented error
    # ...
    def open(self, dbg, uri, persistent):
        """Xapi will call the functions here on VM start/shutdown/suspend/resume/migrate. Every function is idempotent. Every function takes a domain parameter which allows the implementation to track how many domains are currently using the volume."""
        result = {}
        return result
    # ...
        

attach

[attach uri domain] prepares a connection between the storage named by [uri] and the Xen domain with id [domain]. The return value is the information needed by the Xen toolstack to setup the shared-memory blkfront protocol. Note that the same volume may be simultaneously attached to multiple hosts for example over a migrate. If an implementation needs to perform an explicit handover, then it should implement [activate] and [deactivate]. This function is idempotent.

Definition
OCaml example
Python example
Name Direction Type Description
dbg in debug_info Debug context from the caller
uri in uri A URI which represents how to access the volume disk data.
domain in domain An opaque string which represents the Xen domain.
backend out backend The Xen block backend configuration.

Client

(* these directives only needed in a toplevel: *)
#require "xcp-api-client";;
#require "lwt";;
#require "lwt.syntax";;
#require "rpc.unix";;

open S
open Datapath
open Types

module Client = Datapath_client(struct
    include Lwt
    let rpc call = return (Rpc_client.do_rpc ~content_type:`XML ~path:"/" ~host:"127.0.0.1" ~port:80 call) (* TODO: Rpc_client needs to support Lwt *)
end)

let result = Client.attach ~dbg:"string" ~uri:"string" ~domain:"string";;

Server

(* this line only needed in a toplevel: *)
#require "xcp-api-client";;

open S
open Datapath

module Datapath_myimplementation = functor(M: M) -> struct
    (* by default every operation will return a 'not implemented' exception *)
    include Datapath_skeleton(M)
    (* ... *)
    let attach x =
        let open Types.Datapath.Attach in
        let open Types in
        return (`Ok (Out.({ domain_uuid = "string"; implementation = Blkback "string" })))
    (* ... *)
end

Client

        
import xmlrpclib
import xapi
from storage import *

if __name__ == "__main__":
    c = xapi.connect()
    results = c.Datapath.attach({ dbg: "string", uri: "string", domain: "string" })
    print (repr(results))
        

Server

        
import xmlrpclib
import xapi
from storage import *

class Datapath_myimplementation(Datapath_skeleton):
    # by default each method will return a Not_implemented error
    # ...
    def attach(self, dbg, uri, domain):
        """Xapi will call the functions here on VM start/shutdown/suspend/resume/migrate. Every function is idempotent. Every function takes a domain parameter which allows the implementation to track how many domains are currently using the volume."""
        result = {}
        result["backend"] = { "domain_uuid": "string", "implementation": None }
        return result
    # ...
        

activate

[activate uri domain] is called just before a VM needs to read or write its disk. This is an opportunity for an implementation which needs to perform an explicit volume handover to do it. This function is called in the migration downtime window so delays here will be noticeable to users and should be minimised. This function is idempotent.

Definition
OCaml example
Python example
Name Direction Type Description
dbg in debug_info Debug context from the caller
uri in uri A URI which represents how to access the volume disk data.
domain in domain An opaque string which represents the Xen domain.

Client

(* these directives only needed in a toplevel: *)
#require "xcp-api-client";;
#require "lwt";;
#require "lwt.syntax";;
#require "rpc.unix";;

open S
open Datapath
open Types

module Client = Datapath_client(struct
    include Lwt
    let rpc call = return (Rpc_client.do_rpc ~content_type:`XML ~path:"/" ~host:"127.0.0.1" ~port:80 call) (* TODO: Rpc_client needs to support Lwt *)
end)

let result = Client.activate ~dbg:"string" ~uri:"string" ~domain:"string";;

Server

(* this line only needed in a toplevel: *)
#require "xcp-api-client";;

open S
open Datapath

module Datapath_myimplementation = functor(M: M) -> struct
    (* by default every operation will return a 'not implemented' exception *)
    include Datapath_skeleton(M)
    (* ... *)
    let activate x =
        let open Types.Datapath.Activate in
        let open Types in
        return (`Ok ())
    (* ... *)
end

Client

        
import xmlrpclib
import xapi
from storage import *

if __name__ == "__main__":
    c = xapi.connect()
    results = c.Datapath.activate({ dbg: "string", uri: "string", domain: "string" })
    print (repr(results))
        

Server

        
import xmlrpclib
import xapi
from storage import *

class Datapath_myimplementation(Datapath_skeleton):
    # by default each method will return a Not_implemented error
    # ...
    def activate(self, dbg, uri, domain):
        """Xapi will call the functions here on VM start/shutdown/suspend/resume/migrate. Every function is idempotent. Every function takes a domain parameter which allows the implementation to track how many domains are currently using the volume."""
        result = {}
        return result
    # ...
        

deactivate

[deactivate uri domain] is called as soon as a VM has finished reading or writing its disk. This is an opportunity for an implementation which needs to perform an explicit volume handover to do it. This function is called in the migration downtime window so delays here will be noticeable to users and should be minimised. This function is idempotent.

Definition
OCaml example
Python example
Name Direction Type Description
dbg in debug_info Debug context from the caller
uri in uri A URI which represents how to access the volume disk data.
domain in domain An opaque string which represents the Xen domain.

Client

(* these directives only needed in a toplevel: *)
#require "xcp-api-client";;
#require "lwt";;
#require "lwt.syntax";;
#require "rpc.unix";;

open S
open Datapath
open Types

module Client = Datapath_client(struct
    include Lwt
    let rpc call = return (Rpc_client.do_rpc ~content_type:`XML ~path:"/" ~host:"127.0.0.1" ~port:80 call) (* TODO: Rpc_client needs to support Lwt *)
end)

let result = Client.deactivate ~dbg:"string" ~uri:"string" ~domain:"string";;

Server

(* this line only needed in a toplevel: *)
#require "xcp-api-client";;

open S
open Datapath

module Datapath_myimplementation = functor(M: M) -> struct
    (* by default every operation will return a 'not implemented' exception *)
    include Datapath_skeleton(M)
    (* ... *)
    let deactivate x =
        let open Types.Datapath.Deactivate in
        let open Types in
        return (`Ok ())
    (* ... *)
end

Client

        
import xmlrpclib
import xapi
from storage import *

if __name__ == "__main__":
    c = xapi.connect()
    results = c.Datapath.deactivate({ dbg: "string", uri: "string", domain: "string" })
    print (repr(results))
        

Server

        
import xmlrpclib
import xapi
from storage import *

class Datapath_myimplementation(Datapath_skeleton):
    # by default each method will return a Not_implemented error
    # ...
    def deactivate(self, dbg, uri, domain):
        """Xapi will call the functions here on VM start/shutdown/suspend/resume/migrate. Every function is idempotent. Every function takes a domain parameter which allows the implementation to track how many domains are currently using the volume."""
        result = {}
        return result
    # ...
        

detach

[detach uri domain] is called sometime after a VM has finished reading or writing its disk. This is an opportunity to clean up any resources associated with the disk. This function is called outside the migration downtime window so can be slow without affecting users. This function is idempotent. This function should never fail. If an implementation is unable to perform some cleanup right away then it should queue the action internally. Any error result represents a bug in the implementation.

Definition
OCaml example
Python example
Name Direction Type Description
dbg in debug_info Debug context from the caller
uri in uri A URI which represents how to access the volume disk data.
domain in domain An opaque string which represents the Xen domain.

Client

(* these directives only needed in a toplevel: *)
#require "xcp-api-client";;
#require "lwt";;
#require "lwt.syntax";;
#require "rpc.unix";;

open S
open Datapath
open Types

module Client = Datapath_client(struct
    include Lwt
    let rpc call = return (Rpc_client.do_rpc ~content_type:`XML ~path:"/" ~host:"127.0.0.1" ~port:80 call) (* TODO: Rpc_client needs to support Lwt *)
end)

let result = Client.detach ~dbg:"string" ~uri:"string" ~domain:"string";;

Server

(* this line only needed in a toplevel: *)
#require "xcp-api-client";;

open S
open Datapath

module Datapath_myimplementation = functor(M: M) -> struct
    (* by default every operation will return a 'not implemented' exception *)
    include Datapath_skeleton(M)
    (* ... *)
    let detach x =
        let open Types.Datapath.Detach in
        let open Types in
        return (`Ok ())
    (* ... *)
end

Client

        
import xmlrpclib
import xapi
from storage import *

if __name__ == "__main__":
    c = xapi.connect()
    results = c.Datapath.detach({ dbg: "string", uri: "string", domain: "string" })
    print (repr(results))
        

Server

        
import xmlrpclib
import xapi
from storage import *

class Datapath_myimplementation(Datapath_skeleton):
    # by default each method will return a Not_implemented error
    # ...
    def detach(self, dbg, uri, domain):
        """Xapi will call the functions here on VM start/shutdown/suspend/resume/migrate. Every function is idempotent. Every function takes a domain parameter which allows the implementation to track how many domains are currently using the volume."""
        result = {}
        return result
    # ...
        

close

[close uri] is called after a disk is detached and a VM shutdown. This is an opportunity to throw away writes if the disk is not persistent.

Definition
OCaml example
Python example
Name Direction Type Description
dbg in debug_info Debug context from the caller
uri in uri A URI which represents how to access the volume disk data.

Client

(* these directives only needed in a toplevel: *)
#require "xcp-api-client";;
#require "lwt";;
#require "lwt.syntax";;
#require "rpc.unix";;

open S
open Datapath
open Types

module Client = Datapath_client(struct
    include Lwt
    let rpc call = return (Rpc_client.do_rpc ~content_type:`XML ~path:"/" ~host:"127.0.0.1" ~port:80 call) (* TODO: Rpc_client needs to support Lwt *)
end)

let result = Client.close ~dbg:"string" ~uri:"string";;

Server

(* this line only needed in a toplevel: *)
#require "xcp-api-client";;

open S
open Datapath

module Datapath_myimplementation = functor(M: M) -> struct
    (* by default every operation will return a 'not implemented' exception *)
    include Datapath_skeleton(M)
    (* ... *)
    let close x =
        let open Types.Datapath.Close in
        let open Types in
        return (`Ok ())
    (* ... *)
end

Client

        
import xmlrpclib
import xapi
from storage import *

if __name__ == "__main__":
    c = xapi.connect()
    results = c.Datapath.close({ dbg: "string", uri: "string" })
    print (repr(results))
        

Server

        
import xmlrpclib
import xapi
from storage import *

class Datapath_myimplementation(Datapath_skeleton):
    # by default each method will return a Not_implemented error
    # ...
    def close(self, dbg, uri):
        """Xapi will call the functions here on VM start/shutdown/suspend/resume/migrate. Every function is idempotent. Every function takes a domain parameter which allows the implementation to track how many domains are currently using the volume."""
        result = {}
        return result
    # ...
        

exceptions

Name Type Description
Unimplemented
string
The operation has not been implemented