/**
* struct mgmt_msg_edit_reply - frontend edit reply.
*
- * @data: the xpath of the data node that was created.
+ * @changed: If true then changes in datastore resulted.
+ * @created: If true then object was newly created (non-existing before)
+ * @data: @vsplit values, second value may be zero len.
+ * @data: [0] the xpath of the data node that was created.
+ * @data: [1] Possible structured data to pass back to client (e.g., non-"error"
+ * yang modeled error data).
*/
struct mgmt_msg_edit_reply {
struct mgmt_msg_header;
- uint8_t resv2[8];
+ uint8_t changed;
+ uint8_t created;
+ uint8_t resv2[6];
alignas(8) char data[];
};
static int nb_candidate_edit_tree_add(struct nb_config *candidate,
enum nb_operation operation,
LYD_FORMAT format, const char *xpath,
- const char *data, char *xpath_created,
- char *errmsg, size_t errmsg_len)
+ const char *data, bool *created,
+ char *xpath_created, char *errmsg,
+ size_t errmsg_len)
{
struct lyd_node *tree = NULL;
struct lyd_node *parent = NULL;
}
/* check if the node already exists in candidate */
- if (operation == NB_OP_CREATE_EXCL || operation == NB_OP_REPLACE) {
+ if (operation == NB_OP_CREATE || operation == NB_OP_MODIFY)
+ existing = yang_dnode_get(candidate->dnode, xpath_created);
+ else if (operation == NB_OP_CREATE_EXCL || operation == NB_OP_REPLACE) {
existing = yang_dnode_get(candidate->dnode, xpath_created);
/* if the existing node is implicit default, ignore */
+ /* Q: Is this correct for CREATE_EXCL which is supposed to error
+ * if the resouurce already exists? This is used by RESTCONF
+ * when processing the POST command, for example. RFC8040
+ * doesn't say POST fails if resource exists "unless it was a
+ * default".
+ */
if (existing && (existing->flags & LYD_DEFAULT))
existing = NULL;
LYD_MERGE_DESTRUCT | LYD_MERGE_WITH_FLAGS);
if (err) {
/* if replace failed, restore the original node */
- if (existing) {
+ if (existing && operation == NB_OP_REPLACE) {
if (root) {
/* Restoring the whole config. */
candidate->dnode = existing;
ret = NB_ERR;
goto done;
} else {
+ if (!existing)
+ *created = true;
/*
* Free existing node after replace.
* We're using `lyd_free_siblings` here to free the whole
* siblings if it wasn't root, because the existing node
* was unlinked from the tree.
*/
- if (existing)
+ if (existing && operation == NB_OP_REPLACE)
lyd_free_siblings(existing);
tree = NULL; /* LYD_MERGE_DESTRUCT deleted the tree */
int nb_candidate_edit_tree(struct nb_config *candidate,
enum nb_operation operation, LYD_FORMAT format,
- const char *xpath, const char *data,
+ const char *xpath, const char *data, bool *created,
char *xpath_created, char *errmsg, size_t errmsg_len)
{
int ret = NB_ERR;
case NB_OP_MODIFY:
case NB_OP_REPLACE:
ret = nb_candidate_edit_tree_add(candidate, operation, format,
- xpath, data, xpath_created,
- errmsg, errmsg_len);
+ xpath, data, created,
+ xpath_created, errmsg,
+ errmsg_len);
break;
case NB_OP_DESTROY:
case NB_OP_DELETE:
* data
* New data tree for the node.
*
+ * created
+ * OUT param set accordingly if a node was created or just updated
+ *
* xpath_created
* XPath of the created node if operation is "create".
*
* - NB_ERR for other errors.
*/
extern int nb_candidate_edit_tree(struct nb_config *candidate,
- enum nb_operation operation,
- LYD_FORMAT format, const char *xpath,
- const char *data, char *xpath_created,
+ enum nb_operation operation, LYD_FORMAT format,
+ const char *xpath, const char *data,
+ bool *created, char *xpath_created,
char *errmsg, size_t errmsg_len);
/*
}
static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session,
- uint64_t req_id, const char *xpath)
+ uint64_t req_id, bool changed,
+ bool created, const char *xpath,
+ const char *data)
{
struct mgmt_msg_edit_reply *msg;
int ret;
MTYPE_MSG_NATIVE_EDIT_REPLY);
msg->refer_id = session->session_id;
msg->req_id = req_id;
+ msg->changed = changed;
+ msg->created = created;
msg->code = MGMT_MSG_CODE_EDIT_REPLY;
mgmt_msg_native_xpath_encode(msg, xpath);
+ if (data)
+ mgmt_msg_native_append(msg, data, strlen(data) + 1);
+
__dbg("Sending edit-reply from adapter %s to session-id %" PRIu64
- " req-id %" PRIu64 " len %u",
- session->adapter->name, session->session_id, req_id,
- mgmt_msg_native_get_msg_len(msg));
+ " req-id %" PRIu64 " changed %u created %u len %u",
+ session->adapter->name, session->session_id, req_id, changed,
+ created, mgmt_msg_native_get_msg_len(msg));
ret = fe_adapter_send_native_msg(session->adapter, msg,
mgmt_msg_native_get_msg_len(msg),
int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id,
uint64_t req_id, bool unlock, bool commit,
- const char *xpath, int16_t error,
- const char *errstr)
+ bool created, const char *xpath,
+ int16_t error, const char *errstr)
{
struct mgmt_fe_session_ctx *session;
Mgmtd__DatastoreId ds_id, rds_id;
}
}
- if (error)
+ if (error != 0 && error != -EALREADY)
ret = fe_adapter_send_error(session, req_id, false, error, "%s",
errstr);
else
- ret = fe_adapter_send_edit_reply(session, req_id, xpath);
+ ret = fe_adapter_send_edit_reply(session, req_id, created,
+ !error, xpath, errstr);
if (session->cfg_txn_id != MGMTD_TXN_ID_NONE && !commit)
mgmt_destroy_txn(&session->cfg_txn_id);
* req_id: the req id for the edit message
* unlock: implicit-lock flag was set in the request
* commit: implicit-commit flag was set in the request
- * xpath: the xpath of the data node that was created
+ * created: true if the node was just created
+ * xpath: the xpath of the data node that was created/updated
* error: >0 LY_ERR, < 0 -errno
* errstr: the error string, if error is non-zero
*/
extern int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id,
uint64_t req_id, bool unlock,
- bool commit, const char *xpath,
- int16_t error, const char *errstr);
+ bool commit, bool created,
+ const char *xpath, int16_t error,
+ const char *errstr);
/**
* Send an error back to the FE client using native messaging.
struct mgmt_edit_req {
char xpath_created[XPATH_MAXLEN];
+ bool created;
bool unlock;
};
txn->commit_cfg_req->req.commit_cfg
.edit->unlock,
true,
+ txn->commit_cfg_req->req.commit_cfg
+ .edit->created,
txn->commit_cfg_req->req.commit_cfg
.edit->xpath_created,
success ? 0 : -1,
assert(nb_config);
ret = nb_candidate_edit_tree(nb_config, operation, request_type, xpath,
- data, edit->xpath_created, errstr,
- sizeof(errstr));
+ data, &edit->created, edit->xpath_created,
+ errstr, sizeof(errstr));
if (ret)
goto reply;
}
reply:
mgmt_fe_adapter_send_edit_reply(txn->session_id, txn->txn_id, req_id,
- unlock, commit, edit->xpath_created,
+ unlock, commit, edit->created,
+ edit->xpath_created,
errno_from_nb_error(ret), errstr);
XFREE(MTYPE_MGMTD_TXN_REQ, edit);