netget/client/gnmi/
request.rs1use crate::server::gnmi::{
2 proto::gnmi as pb,
3 semantic::{self, Model},
4 value::{self, Path, Update},
5};
6use serde::Deserialize;
7use serde_json::Value;
8use tonic::Status;
9fn proto() -> String {
10 "PROTO".into()
11}
12fn all() -> String {
13 "ALL".into()
14}
15#[derive(Deserialize)]
16#[serde(deny_unknown_fields)]
17struct Get {
18 #[serde(default)]
19 prefix: Path,
20 #[serde(default)]
21 path: Vec<Path>,
22 #[serde(default = "all")]
23 data_type: String,
24 #[serde(default = "proto")]
25 encoding: String,
26 #[serde(default)]
27 use_models: Vec<Model>,
28}
29#[derive(Deserialize)]
30#[serde(deny_unknown_fields)]
31struct Set {
32 #[serde(default)]
33 prefix: Path,
34 #[serde(default)]
35 delete: Vec<Path>,
36 #[serde(default)]
37 replace: Vec<Update>,
38 #[serde(default)]
39 update: Vec<Update>,
40}
41#[derive(Deserialize)]
42#[serde(deny_unknown_fields)]
43struct Subscription {
44 path: Path,
45 #[serde(default)]
46 mode: Option<String>,
47}
48#[derive(Deserialize)]
49#[serde(deny_unknown_fields)]
50struct Subscribe {
51 #[serde(default)]
52 prefix: Path,
53 mode: String,
54 subscription: Vec<Subscription>,
55 #[serde(default = "proto")]
56 encoding: String,
57 #[serde(default)]
58 updates_only: bool,
59 #[serde(default)]
60 use_models: Vec<Model>,
61}
62pub enum Request {
63 Capabilities(pb::CapabilityRequest),
64 Get(pb::GetRequest),
65 Set(pb::SetRequest),
66 Subscribe(pb::SubscriptionList),
67 Poll,
68 Cancel,
69 Wait,
70 Disconnect,
71}
72fn decode<T: serde::de::DeserializeOwned>(value: &Value) -> Result<T, Status> {
73 serde_json::from_value(value.clone())
74 .map_err(|_| Status::invalid_argument("invalid typed gNMI request"))
75}
76pub fn parse(action: &Value) -> Result<Request, Status> {
77 super::check_action(action)?;
78 Ok(match action["type"].as_str().unwrap_or("") {
79 "disconnect" => Request::Disconnect,
80 "wait_for_more" => Request::Wait,
81 "gnmi_poll" => Request::Poll,
82 "gnmi_cancel" => Request::Cancel,
83 "gnmi_capabilities" => Request::Capabilities(pb::CapabilityRequest { extension: vec![] }),
84 "gnmi_get" => {
85 let request: Get = decode(&action["request"])?;
86 let kind = match request.data_type.as_str() {
87 "ALL" => 0,
88 "CONFIG" => 1,
89 "STATE" => 2,
90 "OPERATIONAL" => 3,
91 _ => return Err(Status::invalid_argument("unknown data_type")),
92 };
93 let request = value::checked(pb::GetRequest {
94 prefix: Some(request.prefix.into_proto()?),
95 path: request
96 .path
97 .into_iter()
98 .map(Path::into_proto)
99 .collect::<Result<_, _>>()?,
100 r#type: kind,
101 encoding: value::encoding(&request.encoding)?,
102 use_models: semantic::model_proto(request.use_models)?,
103 extension: vec![],
104 })?;
105 semantic::get_request(&request)?;
106 Request::Get(request)
107 }
108 "gnmi_set" => {
109 let request: Set = decode(&action["request"])?;
110 let request = value::checked(pb::SetRequest {
111 prefix: Some(request.prefix.into_proto()?),
112 delete: request
113 .delete
114 .into_iter()
115 .map(Path::into_proto)
116 .collect::<Result<_, _>>()?,
117 replace: request
118 .replace
119 .into_iter()
120 .map(Update::into_proto)
121 .collect::<Result<_, _>>()?,
122 update: request
123 .update
124 .into_iter()
125 .map(Update::into_proto)
126 .collect::<Result<_, _>>()?,
127 union_replace: vec![],
128 extension: vec![],
129 })?;
130 semantic::set_request(&request)?;
131 Request::Set(request)
132 }
133 "gnmi_subscribe" => {
134 let request: Subscribe = decode(&action["request"])?;
135 let mode = match request.mode.as_str() {
136 "STREAM" => 0,
137 "ONCE" => 1,
138 "POLL" => 2,
139 _ => return Err(Status::invalid_argument("unknown subscribe mode")),
140 };
141 let list = pb::SubscriptionList {
142 prefix: Some(request.prefix.into_proto()?),
143 subscription: request
144 .subscription
145 .into_iter()
146 .map(|s| {
147 let mode = match s.mode.as_deref().unwrap_or("TARGET_DEFINED") {
148 "TARGET_DEFINED" => 0,
149 "ON_CHANGE" => 1,
150 _ => return Err(Status::unimplemented("SAMPLE is excluded")),
151 };
152 Ok(pb::Subscription {
153 path: Some(s.path.into_proto()?),
154 mode,
155 sample_interval: 0,
156 suppress_redundant: false,
157 heartbeat_interval: 0,
158 })
159 })
160 .collect::<Result<_, Status>>()?,
161 qos: None,
162 mode,
163 allow_aggregation: false,
164 use_models: semantic::model_proto(request.use_models)?,
165 encoding: value::encoding(&request.encoding)?,
166 updates_only: request.updates_only,
167 };
168 semantic::subscription(&list)?;
169 value::checked(pb::SubscribeRequest {
170 request: Some(pb::subscribe_request::Request::Subscribe(list.clone())),
171 extension: vec![],
172 })?;
173 Request::Subscribe(list)
174 }
175 _ => return Err(Status::invalid_argument("unknown gNMI client action")),
176 })
177}