=== OpenDaylight Controller MD-SAL: RESTCONF ==== RESCONF operations overview RESTCONF allows access to datastores in the controller. + There are two datastores: + * Config: Contains data inserted via controller * Operational: Contains other data NOTE: Each request must start with the URI /restconf. + RESTCONF listens on port 8080 for HTTP requests. RESTCONF supports *OPTIONS*, *GET*, *PUT*, *POST*, and *DELETE* operations. Request and response data can either be in the XML or JSON format. XML structures according to yang are defined at: http://tools.ietf.org/html/rfc6020[XML-YANG]. JSON structures are defined at: http://tools.ietf.org/html/draft-lhotka-netmod-yang-json-02[JSON-YANG]. Data in the request must have a correctly set *Content-Type* field in the http header with the allowed value of the media type. The media type of the requested data has to be set in the *Accept* field. Get the media types for each resource by calling the OPTIONS operation. Most of the paths of the pathsRestconf endpoints use https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Concepts#Instance_Identifier[Instance Identifier]. ++ is used in the explanation of the operations. ** + * It must start with : where is a name of the module and is the name of a node in the module. It is sufficient to just use after :. Each has to be separated by /. * can represent a data node which is a list or container yang built-in type. If the data node is a list, there must be defined keys of the list behind the data node name for example, //. * The format : has to be used in this case as well: + Module A has node A1. Module B augments node A1 by adding node X. Module C augments node A1 by adding node X. For clarity, it has to be known which node is X (for example: C:X). For more details about encoding, see: http://tools.ietf.org/html/draft-bierman-netconf-restconf-02#section-5.3.1[RESTCONF 02 - Encoding YANG Instance Identifiers in the Request URI.] ==== Mount point A Node can be behind a mount point. In this case, the URI has to be in format /*yang-ext:mount*/. The first is the path to a mount point and the second is the path to a node behind the mount point. A URI can end in a mount point itself by using /*yang-ext:mount*. + More information on how to actually use mountpoints is available at: https://wiki.opendaylight.org/view/OpenDaylight_Controller:Config:Examples:Netconf[OpenDaylight Controller:Config:Examples:Netconf]. ==== HTTP methods ===== OPTIONS /restconf + * Returns the XML description of the resources with the required request and response media types in Web Application Description Language (WADL) ===== GET /restconf/config/ + * Returns a data node from the Config datastore. * points to a data node which must be retrieved. ===== GET /restconf/operational/ + * Returns the value of the data node from the Operational datastore. * points to a data node which must be retrieved. ===== PUT /restconf/config/ * Updates or creates data in the Config datastore and returns the state about success. * points to a data node which must be stored. *Example:* + ---- PUT http://:8080/restconf/config/module1:foo/bar Content-Type: applicaton/xml ---- *Example with mount point:* + ---- PUT http://:8080/restconf/config/module1:foo1/foo2/yang-ext:mount/module2:foo/bar Content-Type: applicaton/xml ---- ===== POST /restconf/config * Creates the data if it does not exist For example: + ---- POST URL: http://localhost:8080/restconf/config/ content-type: application/yang.data+json JSON payload: { "toaster:toaster" : { "toaster:toasterManufacturer" : "General Electric", "toaster:toasterModelNumber" : "123", "toaster:toasterStatus" : "up" } } ---- ===== POST /restconf/config/ * Creates the data if it does not exist in the Config datastore, and returns the state about success. * points to a data node where data must be stored. * The root element of data must have the namespace (data are in XML) or module name (data are in JSON.) *Example:* + ---- POST http://:8080/restconf/config/module1:foo Content-Type: applicaton/xml/ ---- *Example with mount point:* ---- http://:8080/restconf/config/module1:foo1/foo2/yang-ext:mount/module2:foo Content-Type: applicaton/xml ---- ===== POST /restconf/operations/: * Invokes RPC. * : - is the name of the module and is the name of the RPC in this module. * The Root element of the data sent to RPC must have the name “input”. * The result can be the status code or the retrieved data having the root element “output”. *Example:* + ---- POST http://:8080/restconf/operations/module1:fooRpc Content-Type: applicaton/xml Accept: applicaton/xml … The answer from the server could be: ---- *An example using a JSON payload:* + ---- POST http://localhost:8080/restconf/operations/toaster:make-toast Content-Type: application/yang.data+json { "input" : { "toaster:toasterDoneness" : "10", "toaster:toasterToastType":"wheat-bread" } } ---- NOTE: Even though this is a default for the toasterToastType value in the yang, you still need to define it. ===== DELETE /restconf/config/ * Removes the data node in the Config datastore and returns the state about success. * points to a data node which must be removed. More information is available in the http://tools.ietf.org/html/draft-bierman-netconf-restconf-02[RESTCONF RFC]. ==== How RESTCONF works RESTCONF uses these base classes: + InstanceIdentifier:: Represents the path in the data tree ConsumerSession:: Used for invoking RPCs DataBrokerService:: Offers manipulation with transactions and reading data from the datastores SchemaContext:: Holds information about yang modules MountService:: Returns MountInstance based on the InstanceIdentifier pointing to a mount point MountInstace:: Contains the SchemaContext behind the mount point DataSchemaNode:: Provides information about the schema node SimpleNode:: Possesses the same name as the schema node, and contains the value representing the data node value CompositeNode:: Can contain CompositeNode-s and SimpleNode-s ==== GET in action Figure 1 shows the GET operation with URI restconf/config/M:N where M is the module name, and N is the node name. .Get image::Get.png[width=500] . The requested URI is translated into the InstanceIdentifier which points to the data node. During this translation, the DataSchemaNode that conforms to the data node is obtained. If the data node is behind the mount point, the MountInstance is obtained as well. . RESTCONF asks for the value of the data node from DataBrokerService based on InstanceIdentifier. . DataBrokerService returns CompositeNode as data. . StructuredDataToXmlProvider or StructuredDataToJsonProvider is called based on the *Accept* field from the http request. These two providers can transform CompositeNode regarding DataSchemaNode to an XML or JSON document. . XML or JSON is returned as the answer on the request from the client. ==== PUT in action Figure 2 shows the PUT operation with the URI restconf/config/M:N where M is the module name, and N is the node name. Data is sent in the request either in the XML or JSON format. .Put image::Put.png[width=500] . Input data is sent to JsonToCompositeNodeProvider or XmlToCompositeNodeProvider. The correct provider is selected based on the Content-Type field from the http request. These two providers can transform input data to CompositeNode. However, this CompositeNode does not contain enough information for transactions. . The requested URI is translated into InstanceIdentifier which points to the data node. DataSchemaNode conforming to the data node is obtained during this translation. If the data node is behind the mount point, the MountInstance is obtained as well. . CompositeNode can be normalized by adding additional information from DataSchemaNode. . RESTCONF begins the transaction, and puts CompositeNode with InstanceIdentifier into it. The response on the request from the client is the status code which depends on the result from the transaction. // FIXME: Replace with coretutorials tutorial or point to openflow location ==== Something practical . Create a new flow on the switch openflow:1 in table 2. *HTTP request* + ---- Operation: POST URI: http://192.168.11.1:8080/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/2 Content-Type: application/xml ---- ---- false 1 1 2 111 10 10 false 2 2048 10.0.0.1/24 0 10 0 FooXf22 2 false ---- *HTTP response* + ---- Status: 204 No Content ---- [start=2] . Change _strict_ to _true_ in the previous flow. *HTTP request* + ---- Operation: PUT URI: http://192.168.11.1:8080/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/2/flow/111 Content-Type: application/xml ---- ---- true 1 1 2 111 10 10 false 2 2048 10.0.0.1/24 0 10 0 FooXf22 2 false ---- *HTTP response* + ---- Status: 200 OK ---- [start=3] . Show flow: check that _strict_ is _true_. *HTTP request* + ---- Operation: GET URI: http://192.168.11.1:8080/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/2/flow/111 Accept: application/xml ---- *HTTP response* + ---- Status: 200 OK ---- ---- true 1 1 2 111 10 10 false 2 2048 10.0.0.1/24 0 10 0 FooXf22 2 false ---- [start=4] . Delete the flow created. *HTTP request* + ---- Operation: DELETE URI: http://192.168.11.1:8080/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/2/flow/111 ---- *HTTP response* + ---- Status: 200 OK ----