summaryrefslogtreecommitdiffstats
path: root/src/lib/yang/adaptor.h
blob: 8d1fdf3d95ab0f0a10980dbb356136e43cda8d8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (C) 2018-2022 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef ISC_ADAPTOR_H
#define ISC_ADAPTOR_H 1

#include <exceptions/exceptions.h>
#include <cc/data.h>

namespace isc {
namespace yang {

/// @brief Missing key error.
class MissingKey : public isc::Exception {
public:
    MissingKey(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what)
    {}
};

/// @brief JSON adaptor between canonical Kea and YANG models.
///
/// An adaptor slightly modifies a JSON configuration between canonical Kea
/// what required or rendered by a YANG model, e.g. moving a parameter
/// to/from a parent.
/// The basic adaptor provides a set of tools.
class Adaptor {
public:

    /// @brief Constructor.
    Adaptor();

    /// @brief Destructor.
    virtual ~Adaptor();

    /// @brief Get user context.
    ///
    /// Get user-context and/or comment and return it with the comment
    /// if exists moved inside the user-context (without checking if
    /// there is already a comment as it should never be the case).
    ///
    /// This behavior is used to handle comments. For historical purposes
    /// Kea allows to define comments in some scopes. Once the user-context
    /// has been introduced, the comment (as a separate text field)
    /// disappeared and was moved to comment key within user-context.
    /// Nevertheless, the old syntax is still supported.
    static isc::data::ConstElementPtr
    getContext(isc::data::ConstElementPtr parent);

    /// @brief Moves a parameter from parent to a list of children.
    ///
    /// Move a parameter from the parent to each item in a list.
    /// If the parameter exists in a child, it is skipped for this
    /// particular child, not overridden.
    ///
    /// @param name The parameter name.
    /// @param parent The parent element.
    /// @param list The children list.
    static void fromParent(const std::string& name,
                           isc::data::ConstElementPtr parent,
                           isc::data::ConstElementPtr list);

    /// @brief Moves a parameter to a parent.
    ///
    /// Move a parameter from children to the parent. All children
    /// on the list must have the parameter specified and it has to have
    /// the same value.
    ///
    /// @param name The parameter name.
    /// @param parent The parent element.
    /// @param list The children list.
    static void toParent(const std::string& name,
                         isc::data::ElementPtr parent,
                         isc::data::ConstElementPtr list);

    /// @brief Modify a configuration in its JSON element format.
    ///
    /// Smart merging tool, e.g. completing a from yang configuration.
    ///
    /// A modification is a path and actions:
    ///  - path item can be:
    ///   * a string: current scope is a map, go down following the string
    ///     as a key.
    ///   * a number: current scope is a list, go down the number as an index.
    ///   * special value -1: current scope is a list, apply to all items.
    ///   * map { "<key>": <value> }: current scope is a list, go down to
    ///     the item using the key / value pair.
    ///  - an action can be: insert, replace or delete:
    ///   * insert adds a value at a key:
    ///     . in a map the key is the new entry key
    ///     . in a list an integer key is the new element index
    ///     . in a list a map key is the key / value pair the to-be-modified
    ///       element contains
    ///   * replace adds or replaces if it already exists a value at
    ///     an entry key in a map.
    ///   * delete removes a value designed by a key
    ///
    /// For instance to add a control-socket entry in a configuration
    /// from a generic (vs Kea) model:
    /// @code
    ///   path := [ ]
    ///   actions := [ {
    ///     "action": "insert",
    ///     "key": "Dhcp4",
    ///     "value":
    ///       {
    ///         "control-socket":
    ///           {
    ///              "socket-type": "unix",
    ///              "socket-name": "/tmp/kea4-ctrl-socket"
    ///           }
    ///       }
    ///    }
    /// @endcode
    ///
    /// @param path The search list to follow down to the place to
    ///             apply the action list.
    /// @param actions The action list
    /// @param config The configuration (JSON map) to modify.
    /// @note modify does not throw but returns on unexpected conditions.
    static void modify(isc::data::ConstElementPtr path,
                       isc::data::ConstElementPtr actions,
                       isc::data::ElementPtr config);

};

}  // end of namespace isc::yang
}  // end of namespace isc

#endif // ISC_ADAPTOR_H