zabbix_api/client/v6/
mod.rs

1use std::collections::HashMap;
2
3use log::{debug, error, info};
4use reqwest::blocking::Client;
5use serde::de::DeserializeOwned;
6use serde::Serialize;
7
8use crate::client::jsonrpc::{ZabbixApiRequest, ZabbixApiResponse};
9use crate::client::post::send_post_request;
10use crate::client::ZabbixApiClient;
11use crate::error::ZabbixApiError;
12use crate::host::create::{CreateHostGroupRequest, CreateHostGroupResponse, CreateHostRequest, CreateHostResponse};
13use crate::host::{ZabbixHost, ZabbixHostGroup};
14use crate::item::create::{CreateItemRequest, CreateItemResponse};
15use crate::item::ZabbixItem;
16use crate::trigger::create::{CreateTriggerRequest, CreateTriggerResponse};
17use crate::trigger::ZabbixTrigger;
18use crate::webscenario::create::{CreateWebScenarioRequest, CreateWebScenarioResponse};
19use crate::webscenario::ZabbixWebScenario;
20
21const JSON_RPC_VERSION: &str = "2.0";
22
23/// Zabbix API Client implementation for [Zabbix API v6](https://www.zabbix.com/documentation/6.0/en/manual/api)
24#[derive(Debug,Clone)]
25pub struct ZabbixApiV6Client {
26    client: Client,
27    api_endpoint_url: String
28}
29
30impl ZabbixApiV6Client {
31    pub fn new(client: Client, api_endpoint_url: &str) -> ZabbixApiV6Client {
32        ZabbixApiV6Client {
33            client,
34            api_endpoint_url: api_endpoint_url.to_string()
35        }
36    }
37}
38
39impl ZabbixApiClient for ZabbixApiV6Client {
40
41    /// # get_api_info
42    ///
43    /// Implements `ZabbixApiClient::get_api_info`.
44    ///
45    /// See the trait documentation for more details.
46    fn get_api_info(&self) -> Result<String, ZabbixApiError> {
47        let request = ZabbixApiRequest {
48            jsonrpc: JSON_RPC_VERSION.to_string(),
49            method: "apiinfo.version".to_string(),
50            params: HashMap::<String,String>::new(),
51            id: 1,
52            auth: None,
53        };
54
55        match send_post_request(&self.client, &self.api_endpoint_url, request) {
56            Ok(response_body) => {
57                let response = serde_json::from_str::<ZabbixApiResponse<String>>(&response_body)?;
58
59                match response.result {
60                    Some(api_version) => {
61                        info!("zabbix api version: '{api_version}'");
62                        Ok(api_version)
63                    }
64                    None => {
65                        match response.error {
66                            Some(error) => {
67                                error!("{:?}", error);
68
69                                Err(ZabbixApiError::ApiCallError {
70                                    zabbix: error,
71                                })
72                            }
73                            None => Err(ZabbixApiError::BadRequestError)
74                        }
75                    }
76                }
77            }
78            Err(e) => {
79                error!("{}", e);
80                Err(e)
81            }
82        }
83    }
84
85    /// # get_auth_session
86    ///
87    /// Implements `ZabbixApiClient::get_auth_session`.
88    ///
89    /// See the trait documentation for more details.
90    fn get_auth_session(&self,  login: &str, token: &str) -> Result<String, ZabbixApiError> {
91        info!("getting auth session for user '{login}'..");
92
93        let params = HashMap::from([
94            ("username".to_string(), login.to_string()),
95            ("password".to_string(), token.to_string()),
96        ]);
97
98        let request = ZabbixApiRequest {
99            jsonrpc: JSON_RPC_VERSION.to_string(),
100            method: "user.login".to_string(),
101            params,
102            id: 1,
103            auth: None,
104        };
105
106        match send_post_request(&self.client, &self.api_endpoint_url, request) {
107            Ok(response_body) => {
108                let response = serde_json::from_str::<ZabbixApiResponse<String>>(&response_body)?;
109
110                match response.result {
111                    Some(session) => {
112                        info!("auth ok");
113                        Ok(session)
114                    }
115                    None => {
116                        match response.error {
117                            Some(error) => {
118                                error!("{:?}", error);
119
120                                Err(ZabbixApiError::ApiCallError {
121                                    zabbix: error,
122                                })
123                            }
124                            None => Err(ZabbixApiError::BadRequestError)
125                        }
126                    }
127                }
128            }
129            Err(e) => {
130                error!("{}", e);
131                Err(e)
132            }
133        }
134    }
135
136    /// # raw_api_call
137    ///
138    /// Implements `ZabbixApiClient::raw_api_call`.
139    ///
140    /// See the trait documentation for more details.
141    fn raw_api_call<P: Serialize, R: DeserializeOwned>(&self, session: &str,
142                                           method: &str, params: &P) -> Result<ZabbixApiResponse<R>, ZabbixApiError> {
143        info!("call api method '{method}'..");
144
145        let request = ZabbixApiRequest {
146            jsonrpc: JSON_RPC_VERSION.to_string(),
147            method: method.to_string(),
148            params,
149            id: 1,
150            auth: Some(session.to_string()),
151        };
152
153        match send_post_request(&self.client, &self.api_endpoint_url, request) {
154            Ok(response_body) => {
155                debug!("[response body]");
156                debug!("{response_body}");
157                debug!("[/response body]");
158
159                let response = serde_json::from_str::<ZabbixApiResponse<R>>(&response_body)?;
160
161                match response.result {
162                    Some(_) => {
163                        info!("api method '{method}' has been successfully called");
164                        Ok(response)
165                    }
166                    None => {
167                        match response.error {
168                            Some(error) => {
169                                error!("{:?}", error);
170
171                                Err(ZabbixApiError::ApiCallError {
172                                    zabbix: error,
173                                })
174                            }
175                            None => Err(ZabbixApiError::BadRequestError)
176                        }
177                    }
178                }
179            }
180            Err(e) => {
181                error!("{}", e);
182                Err(e)
183            }
184        }
185    }
186
187    /// # get_host_groups
188    ///
189    /// Implements `ZabbixApiClient::get_host_groups`.
190    ///
191    /// See the trait documentation for more details.
192    fn get_host_groups<P: Serialize>(&self, session: &str, params: &P) -> Result<Vec<ZabbixHostGroup>, ZabbixApiError> {
193        info!("getting host groups with params");
194
195        let api_request = ZabbixApiRequest {
196            jsonrpc: JSON_RPC_VERSION.to_string(),
197            method: "hostgroup.get".to_string(),
198            params,
199            id: 1,
200            auth: Some(session.to_string()),
201        };
202
203        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
204            Ok(response_body) => {
205                debug!("[response body]");
206                debug!("{response_body}");
207                debug!("[/response body]");
208
209                let response = serde_json::from_str::<ZabbixApiResponse<Vec<ZabbixHostGroup>>>(&response_body)?;
210
211                match response.result {
212                    Some(results) => {
213                        info!("host groups found: {:?}", results);
214                        Ok(results)
215                    }
216                    None => {
217                        match response.error {
218                            Some(error) => {
219                                error!("{:?}", error);
220
221                                Err(ZabbixApiError::ApiCallError {
222                                    zabbix: error,
223                                })
224                            }
225                            None => Err(ZabbixApiError::BadRequestError)
226                        }
227                    }
228                }
229            }
230            Err(e) => {
231                error!("{}", e);
232                Err(e)
233            }
234        }
235    }
236
237    /// # get_hosts
238    ///
239    /// Implements `ZabbixApiClient::get_hosts`.
240    ///
241    /// See the trait documentation for more details.
242    fn get_hosts<P: Serialize>(&self, session: &str, params: &P) -> Result<Vec<ZabbixHost>, ZabbixApiError> {
243        info!("getting hosts with params");
244
245        let api_request = ZabbixApiRequest {
246            jsonrpc: JSON_RPC_VERSION.to_string(),
247            method: "host.get".to_string(),
248            params,
249            id: 1,
250            auth: Some(session.to_string()),
251        };
252
253        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
254            Ok(response_body) => {
255                debug!("[response body]");
256                debug!("{response_body}");
257                debug!("[/response body]");
258
259                let response = serde_json::from_str::<ZabbixApiResponse<Vec<ZabbixHost>>>(&response_body)?;
260
261                match response.result {
262                    Some(results) => {
263                        info!("hosts found: {:?}", results);
264                        Ok(results)
265                    }
266                    None => {
267                        match response.error {
268                            Some(error) => {
269                                error!("{:?}", error);
270
271                                Err(ZabbixApiError::ApiCallError {
272                                    zabbix: error,
273                                })
274                            }
275                            None => Err(ZabbixApiError::BadRequestError)
276                        }
277                    }
278                }
279            }
280            Err(e) => {
281                error!("{}", e);
282                Err(e)
283            }
284        }
285    }
286
287    /// # get_items
288    ///
289    /// Implements `ZabbixApiClient::get_items`.
290    ///
291    /// See the trait documentation for more details.
292    fn get_items<P: Serialize>(&self, session: &str, params: &P) -> Result<Vec<ZabbixItem>, ZabbixApiError> {
293        info!("getting items with params");
294
295        let api_request = ZabbixApiRequest {
296            jsonrpc: JSON_RPC_VERSION.to_string(),
297            method: "item.get".to_string(),
298            params,
299            id: 1,
300            auth: Some(session.to_string()),
301        };
302
303        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
304            Ok(response_body) => {
305                debug!("[response body]");
306                debug!("{response_body}");
307                debug!("[/response body]");
308
309                let response = serde_json::from_str::<ZabbixApiResponse<Vec<ZabbixItem>>>(&response_body)?;
310
311                match response.result {
312                    Some(results) => {
313                        info!("hosts found: {:?}", results);
314                        Ok(results)
315                    }
316                    None => {
317                        match response.error {
318                            Some(error) => {
319                                error!("{:?}", error);
320
321                                Err(ZabbixApiError::ApiCallError {
322                                    zabbix: error,
323                                })
324                            }
325                            None => Err(ZabbixApiError::BadRequestError)
326                        }
327                    }
328                }
329            }
330            Err(e) => {
331                error!("{}", e);
332                Err(e)
333            }
334        }
335    }
336
337    /// # get_triggers
338    ///
339    /// Implements `ZabbixApiClient::get_triggers`.
340    ///
341    /// See the trait documentation for more details.
342    fn get_triggers<P: Serialize>(&self, session: &str, params: &P) -> Result<Vec<ZabbixTrigger>, ZabbixApiError> {
343        info!("getting triggers..");
344
345        let api_request = ZabbixApiRequest {
346            jsonrpc: JSON_RPC_VERSION.to_string(),
347            method: "trigger.get".to_string(),
348            params,
349            id: 1,
350            auth: Some(session.to_string()),
351        };
352
353        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
354            Ok(response_body) => {
355                debug!("[response body]");
356                debug!("{response_body}");
357                debug!("[/response body]");
358
359                let response = serde_json::from_str::<ZabbixApiResponse<Vec<ZabbixTrigger>>>(&response_body)?;
360
361                match response.result {
362                    Some(results) => {
363                        info!("hosts found: {:?}", results);
364                        Ok(results)
365                    }
366                    None => {
367                        match response.error {
368                            Some(error) => {
369                                error!("{:?}", error);
370
371                                Err(ZabbixApiError::ApiCallError {
372                                    zabbix: error,
373                                })
374                            }
375                            None => Err(ZabbixApiError::BadRequestError)
376                        }
377                    }
378                }
379            }
380            Err(e) => {
381                error!("{}", e);
382                Err(e)
383            }
384        }
385    }
386
387    /// # get_webscenarios
388    ///
389    /// Implements `ZabbixApiClient::get_webscenarios`.
390    ///
391    /// See the trait documentation for more details.
392    fn get_webscenarios<P: Serialize>(&self, session: &str, params: &P) -> Result<Vec<ZabbixWebScenario>, ZabbixApiError> {
393        info!("getting web-scenarios..");
394
395        let api_request = ZabbixApiRequest {
396            jsonrpc: JSON_RPC_VERSION.to_string(),
397            method: "httptest.get".to_string(),
398            params,
399            id: 1,
400            auth: Some(session.to_string()),
401        };
402
403        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
404            Ok(response_body) => {
405                debug!("[response body]");
406                debug!("{response_body}");
407                debug!("[/response body]");
408
409                let response = serde_json::from_str::<ZabbixApiResponse<Vec<ZabbixWebScenario>>>(&response_body)?;
410
411                match response.result {
412                    Some(results) => {
413                        info!("hosts found: {:?}", results);
414                        Ok(results)
415                    }
416                    None => {
417                        match response.error {
418                            Some(error) => {
419                                error!("{:?}", error);
420
421                                Err(ZabbixApiError::ApiCallError {
422                                    zabbix: error,
423                                })
424                            }
425                            None => Err(ZabbixApiError::BadRequestError)
426                        }
427                    }
428                }
429            }
430            Err(e) => {
431                error!("{}", e);
432                Err(e)
433            }
434        }
435    }
436
437    /// # create_host_group
438    ///
439    /// Implements `ZabbixApiClient::create_host_group`.
440    ///
441    /// See the trait documentation for more details.
442    fn create_host_group(&self, session: &str, request: &CreateHostGroupRequest) -> Result<u32, ZabbixApiError> {
443        info!("creating host group '{}'..", request.name);
444
445        let api_request = ZabbixApiRequest {
446            jsonrpc: JSON_RPC_VERSION.to_string(),
447            method: "hostgroup.create".to_string(),
448            params: request,
449            id: 1,
450            auth: Some(session.to_string()),
451        };
452
453        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
454            Ok(response_body) => {
455                debug!("[response body]");
456                debug!("{response_body}");
457                debug!("[/response body]");
458
459                let response = serde_json::from_str::<ZabbixApiResponse<CreateHostGroupResponse>>(&response_body)?;
460
461                match response.result {
462                    Some(result) => {
463                        info!("host group '{}' has been created", request.name);
464
465                        match result.group_ids.first() {
466                            Some(id) => {
467                                id.parse::<u32>().map_err(|_| ZabbixApiError::Error)
468                            }
469                            None => {
470                                error!("unexpected error, server returned empty id list");
471                                Err(ZabbixApiError::Error)
472                            }
473                        }
474                    }
475                    None => {
476                        match response.error {
477                            Some(error) => {
478                                error!("{:?}", error);
479
480                                Err(ZabbixApiError::ApiCallError {
481                                    zabbix: error,
482                                })
483                            }
484                            None => Err(ZabbixApiError::BadRequestError)
485                        }
486                    }
487                }
488            }
489            Err(e) => {
490                error!("{}", e);
491                Err(e)
492            }
493        }
494    }
495
496    /// # create_host
497    ///
498    /// Implements `ZabbixApiClient::create_host`.
499    ///
500    /// See the trait documentation for more details.
501    fn create_host(&self, session: &str, request: &CreateHostRequest) -> Result<u32, ZabbixApiError> {
502        info!("creating host '{}'..", request.host);
503
504        let api_request = ZabbixApiRequest {
505            jsonrpc: JSON_RPC_VERSION.to_string(),
506            method: "host.create".to_string(),
507            params: request,
508            id: 1,
509            auth: Some(session.to_string()),
510        };
511
512        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
513            Ok(response_body) => {
514                debug!("[response body]");
515                debug!("{response_body}");
516                debug!("[/response body]");
517
518                let response = serde_json::from_str::<ZabbixApiResponse<CreateHostResponse>>(&response_body)?;
519
520                match response.result {
521                    Some(result) => {
522
523                        info!("host '{}' has been created", request.host);
524
525                        match result.host_ids.first() {
526                            Some(host_id) => {
527                                host_id.parse::<u32>().map_err(|_| ZabbixApiError::Error)
528                            }
529                            None => {
530                                error!("unexpected error, server returned empty id list");
531                                Err(ZabbixApiError::Error)
532                            }
533                        }
534                    }
535                    None => {
536                        match response.error {
537                            Some(error) => {
538                                error!("{:?}", error);
539
540                                Err(ZabbixApiError::ApiCallError {
541                                    zabbix: error,
542                                })
543                            }
544                            None => Err(ZabbixApiError::BadRequestError)
545                        }
546                    }
547                }
548            }
549            Err(e) => {
550                error!("{}", e);
551                Err(e)
552            }
553        }
554    }
555
556    /// # create_item
557    ///
558    /// Implements `ZabbixApiClient::create_item`.
559    ///
560    /// See the trait documentation for more details.
561    fn create_item(&self, session: &str, request: &CreateItemRequest) -> Result<u32, ZabbixApiError> {
562        info!("creating item with key '{}' for host id {}..", request.key_, request.host_id);
563
564        let api_request = ZabbixApiRequest {
565            jsonrpc: JSON_RPC_VERSION.to_string(),
566            method: "item.create".to_string(),
567            params: request,
568            id: 1,
569            auth: Some(session.to_string()),
570        };
571
572        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
573            Ok(response_body) => {
574                debug!("[response body]");
575                debug!("{response_body}");
576                debug!("[/response body]");
577
578                let response = serde_json::from_str::<ZabbixApiResponse<CreateItemResponse>>(&response_body)?;
579
580                match response.result {
581                    Some(result) => {
582
583                        info!("item '{}' has been created", request.key_);
584
585                        match result.item_ids.first() {
586                            Some(host_id) => {
587                                host_id.parse::<u32>().map_err(|_| ZabbixApiError::Error)
588                            }
589                            None => {
590                                error!("unexpected error, server returned empty id list");
591                                Err(ZabbixApiError::Error)
592                            }
593                        }
594                    }
595                    None => {
596                        match response.error {
597                            Some(error) => {
598                                error!("{:?}", error);
599
600                                Err(ZabbixApiError::ApiCallError {
601                                    zabbix: error,
602                                })
603                            }
604                            None => Err(ZabbixApiError::BadRequestError)
605                        }
606                    }
607                }
608            }
609            Err(e) => {
610                error!("{}", e);
611                Err(e)
612            }
613        }
614    }
615
616    /// # create_trigger
617    ///
618    /// Implements `ZabbixApiClient::create_trigger`.
619    ///
620    /// See the trait documentation for more details.
621    fn create_trigger(&self, session: &str, request: &CreateTriggerRequest) -> Result<u32, ZabbixApiError> {
622        info!("creating trigger '{}' with expression '{}'..", request.description, request.expression);
623
624        let api_request = ZabbixApiRequest {
625            jsonrpc: JSON_RPC_VERSION.to_string(),
626            method: "trigger.create".to_string(),
627            params: request,
628            id: 1,
629            auth: Some(session.to_string()),
630        };
631
632        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
633            Ok(response_body) => {
634                debug!("[response body]");
635                debug!("{response_body}");
636                debug!("[/response body]");
637
638                let response = serde_json::from_str::<ZabbixApiResponse<CreateTriggerResponse>>(&response_body)?;
639
640                match response.result {
641                    Some(result) => {
642
643                        info!("trigger '{}' has been created", request.description);
644
645                        match result.trigger_ids.first() {
646                            Some(host_id) => {
647                                host_id.parse::<u32>().map_err(|_| ZabbixApiError::Error)
648                            }
649                            None => {
650                                error!("unexpected error, server returned empty id list");
651                                Err(ZabbixApiError::Error)
652                            }
653                        }
654                    }
655                    None => {
656                        match response.error {
657                            Some(error) => {
658                                error!("{:?}", error);
659
660                                Err(ZabbixApiError::ApiCallError {
661                                    zabbix: error,
662                                })
663                            }
664                            None => Err(ZabbixApiError::BadRequestError)
665                        }
666                    }
667                }
668            }
669            Err(e) => {
670                error!("{}", e);
671                Err(e)
672            }
673        }
674    }
675
676    /// # create_webscenario
677    ///
678    /// Implements `ZabbixApiClient::create_webscenario`.
679    ///
680    /// See the trait documentation for more details.
681    fn create_webscenario(&self, session: &str, request: &CreateWebScenarioRequest) -> Result<u32, ZabbixApiError> {
682        info!("creating web-scenario '{}' for host id '{}'..", request.name, request.host_id);
683
684        let api_request = ZabbixApiRequest {
685            jsonrpc: JSON_RPC_VERSION.to_string(),
686            method: "httptest.create".to_string(),
687            params: request,
688            id: 1,
689            auth: Some(session.to_string()),
690        };
691
692        match send_post_request(&self.client, &self.api_endpoint_url, api_request) {
693            Ok(response_body) => {
694                debug!("[response body]");
695                debug!("{response_body}");
696                debug!("[/response body]");
697
698                let response = serde_json::from_str::<ZabbixApiResponse<CreateWebScenarioResponse>>(&response_body)?;
699
700                match response.result {
701                    Some(result) => {
702
703                        info!("web-scenario '{}' has been created", request.name);
704
705                        match result.http_test_ids.first() {
706                            Some(host_id) => {
707                                host_id.parse::<u32>().map_err(|_| ZabbixApiError::Error)
708                            }
709                            None => {
710                                error!("unexpected error, server returned empty id list");
711                                Err(ZabbixApiError::Error)
712                            }
713                        }
714                    }
715                    None => {
716                        match response.error {
717                            Some(error) => {
718                                error!("{:?}", error);
719
720                                Err(ZabbixApiError::ApiCallError {
721                                    zabbix: error,
722                                })
723                            }
724                            None => Err(ZabbixApiError::BadRequestError)
725                        }
726                    }
727                }
728            }
729            Err(e) => {
730                error!("{}", e);
731                Err(e)
732            }
733        }
734    }
735}
736
737#[cfg(test)]
738mod tests {
739    use std::error::Error;
740
741    use log::{error, info};
742    use reqwest::blocking::Client;
743    use serde::Serialize;
744
745    use crate::client::v6::ZabbixApiV6Client;
746    use crate::client::ZabbixApiClient;
747    use crate::host::get::{GetHostGroupsRequest, GetHostsRequest};
748    use crate::host::ZabbixHost;
749    use crate::item::create::CreateItemRequest;
750    use crate::item::get::GetItemsRequestById;
751    use crate::tests::builder::TestEnvBuilder;
752    use crate::tests::integration::{are_integration_tests_enabled, get_integration_tests_config};
753    use crate::tests::{get_random_string, init_logging};
754    use crate::trigger::create::CreateTriggerRequest;
755    use crate::trigger::get::GetTriggerByIdRequest;
756    use crate::webscenario::create::CreateWebScenarioRequest;
757    use crate::webscenario::get::GetWebScenarioByIdRequest;
758    use crate::webscenario::ZabbixWebScenarioStep;
759    use crate::ZABBIX_EXTEND_PROPERTY_VALUE;
760
761    #[test]
762    fn get_api_info() {
763        if are_integration_tests_enabled() {
764            let test_env = TestEnvBuilder::build();
765
766            match test_env.client.get_api_info() {
767                Ok(result) => {
768                    assert!(!result.is_empty())
769                }
770                Err(e) => {
771                    error!("error: {}", e);
772                    panic!("unexpected error")
773                }
774            }
775        }
776    }
777
778    #[test]
779    fn session_should_be_returned() {
780        init_logging();
781
782        if are_integration_tests_enabled() {
783            let http_client = Client::new();
784
785            let tests_config = get_integration_tests_config();
786
787            let client = ZabbixApiV6Client::new(http_client, &tests_config.zabbix_api_url);
788
789            match client.get_auth_session(&tests_config.zabbix_api_user, &tests_config.zabbix_api_password) {
790                Ok(session) => assert!(session.len() > 0),
791                Err(e) => {
792                    error!("error: {}", e);
793                    panic!("unexpected error")
794                }
795            }
796        }
797    }
798
799    #[test]
800    fn raw_api_call_test() {
801        init_logging();
802
803        if are_integration_tests_enabled() {
804            let mut test_env = TestEnvBuilder::build();
805            test_env.get_session();
806
807            #[derive(Serialize)]
808            struct Params {
809                pub filter: Filter
810            }
811
812            #[derive(Serialize)]
813            struct Filter {
814                pub host: Vec<String>
815            }
816
817            let params = Params {
818                filter: Filter {
819                    host: vec!["Zabbix server".to_string()],
820                },
821            };
822
823            match test_env.client.raw_api_call::<Params, Vec<ZabbixHost>>(
824                &test_env.session, "host.get", &params) {
825
826                Ok(response) => {
827                    let results = response.result.unwrap();
828                    info!("{:?}", results.first().unwrap());
829                    assert_eq!(1, results.len())
830                }
831                Err(e) => {
832                    error!("api call error: {}", e);
833                    panic!("unexpected api call error")
834                }
835            }
836        }
837    }
838
839    #[test]
840    fn get_host_groups_test() {
841        init_logging();
842
843        if are_integration_tests_enabled() {
844            let mut test_env = TestEnvBuilder::build();
845
846            let group_name = get_random_string();
847            let group_name2 = get_random_string();
848            let group_name3 = get_random_string();
849
850            test_env.get_session()
851                .create_host_group(&group_name)
852                .create_host_group(&group_name2)
853                .create_host_group(&group_name3);
854
855            #[derive(Serialize)]
856            struct Filter {
857                pub name: Vec<String>
858            }
859
860            let request = GetHostGroupsRequest {
861                output: ZABBIX_EXTEND_PROPERTY_VALUE.to_string(),
862                filter: Filter {
863                    name: vec![group_name2.to_string()],
864                },
865            };
866
867            match test_env.client.get_host_groups(&test_env.session, &request) {
868                Ok(host_groups) => {
869                    assert_eq!(host_groups.len(), 1);
870
871                    let host_group = host_groups.first().unwrap();
872
873                    assert_eq!(&host_group.name, &group_name2)
874                }
875                Err(e) => {
876                    if let Some(inner_source) = e.source() {
877                        println!("Caused by: {}", inner_source);
878                    }
879
880                    error!("host group get error: {}", e);
881                    panic!("{}", e)
882                }
883            }
884        }
885    }
886
887    #[test]
888    fn get_hosts_test() {
889        init_logging();
890
891        if are_integration_tests_enabled() {
892            let mut test_env = TestEnvBuilder::build();
893
894            let group_name = get_random_string();
895            let host_name1 = get_random_string();
896            let host_name2 = get_random_string();
897            let host_name3 = get_random_string();
898
899            test_env.get_session()
900                .create_host_group(&group_name)
901                .create_host(&host_name1)
902                .create_host(&host_name2)
903                .create_host(&host_name3);
904
905            #[derive(Serialize)]
906            struct Filter {
907                pub host: Vec<String>
908            }
909
910            let request = GetHostsRequest {
911                filter: Filter {
912                    host: vec![host_name2.to_string()],
913                },
914            };
915
916            match test_env.client.get_hosts(&test_env.session, &request) {
917                Ok(hosts) => {
918                    assert_eq!(hosts.len(), 1);
919
920                    let host = hosts.first().unwrap();
921
922                    assert_eq!(&host.host, &host_name2)
923                }
924                Err(e) => {
925                    if let Some(inner_source) = e.source() {
926                        println!("Caused by: {}", inner_source);
927                    }
928
929                    error!("host get error: {}", e);
930                    panic!("{}", e)
931                }
932            }
933        }
934    }
935
936    #[test]
937    fn get_items_test() {
938        init_logging();
939
940        if are_integration_tests_enabled() {
941            let mut test_env = TestEnvBuilder::build();
942
943            let group_name = get_random_string();
944            let host_name1 = get_random_string();
945            let host_name2 = get_random_string();
946            let host_name3 = get_random_string();
947            let item_name = get_random_string();
948            let item_key = format!("test{}", get_random_string());
949
950            test_env.get_session()
951                .create_host_group(&group_name)
952                .create_host(&host_name1)
953                .create_host(&host_name2)
954                .create_host(&host_name3)
955                .create_item(&item_name, &item_key);
956
957            #[derive(Serialize)]
958            struct Search {
959                pub key_: String
960            }
961
962            let request = GetItemsRequestById {
963                output: ZABBIX_EXTEND_PROPERTY_VALUE.to_string(),
964                with_triggers: false,
965                host_ids: test_env.latest_host_id.to_string(),
966                search: Search {
967                    key_: item_key.to_string(),
968                },
969                sort_field: "name".to_string(),
970            };
971
972            match test_env.client.get_items(&test_env.session, &request) {
973                Ok(items) => {
974                    assert_eq!(items.len(), 1);
975
976                    let item = items.first().unwrap();
977
978                    assert_eq!(&item.key_, &item_key)
979                }
980                Err(e) => {
981                    if let Some(inner_source) = e.source() {
982                        println!("Caused by: {}", inner_source);
983                    }
984
985                    error!("host get error: {}", e);
986                    panic!("{}", e)
987                }
988            }
989        }
990    }
991
992    #[test]
993    fn get_triggers_test() {
994        init_logging();
995
996        if are_integration_tests_enabled() {
997            let mut test_env = TestEnvBuilder::build();
998
999            let group_name = get_random_string();
1000            let host_name = get_random_string();
1001            let item_name = get_random_string();
1002            let item_key = get_random_string();
1003            let trigger_description = get_random_string();
1004
1005            test_env.get_session()
1006                .create_host_group(&group_name)
1007                .create_host(&host_name)
1008                .create_item(&item_name, &item_key)
1009                .create_trigger(&trigger_description, &format!("last(/{host_name}/{item_key})=0"));
1010
1011            let request = GetTriggerByIdRequest {
1012                trigger_ids: test_env.latest_trigger_id.to_string(),
1013                output: ZABBIX_EXTEND_PROPERTY_VALUE.to_string(),
1014                select_functions: ZABBIX_EXTEND_PROPERTY_VALUE.to_string(),
1015            };
1016
1017            match test_env.client.get_triggers(&test_env.session, &request) {
1018                Ok(results) => {
1019                    assert_eq!(results.len(), 1);
1020                    let result = results.first().unwrap();
1021
1022                    assert_eq!(&result.description, &trigger_description)
1023                }
1024                Err(e) => {
1025                    if let Some(inner_source) = e.source() {
1026                        println!("Caused by: {}", inner_source);
1027                    }
1028
1029                    error!("host get error: {}", e);
1030                    panic!("{}", e)
1031                }
1032            }
1033        }
1034    }
1035
1036    #[test]
1037    fn get_webscenarios_test() {
1038        init_logging();
1039
1040        if are_integration_tests_enabled() {
1041            let mut test_env = TestEnvBuilder::build();
1042
1043            let group_name = get_random_string();
1044            let host_name = get_random_string();
1045            let item_name = get_random_string();
1046            let item_key = get_random_string();
1047            let trigger_description = get_random_string();
1048            let webscenario_name = get_random_string();
1049
1050            test_env.get_session()
1051                .create_host_group(&group_name)
1052                .create_host(&host_name)
1053                .create_item(&item_name, &item_key)
1054                .create_trigger(&trigger_description, &format!("last(/{host_name}/{item_key})=0"))
1055                .create_web_scenario(&webscenario_name);
1056
1057            let request = GetWebScenarioByIdRequest {
1058                output: ZABBIX_EXTEND_PROPERTY_VALUE.to_string(),
1059                select_steps: ZABBIX_EXTEND_PROPERTY_VALUE.to_string(),
1060                httptest_ids: test_env.latest_webscenario_id.to_string(),
1061            };
1062
1063            match test_env.client.get_webscenarios(&test_env.session, &request) {
1064                Ok(results) => {
1065                    assert_eq!(results.len(), 1);
1066                    let result = results.first().unwrap();
1067
1068                    assert_eq!(&result.name, &webscenario_name)
1069                }
1070                Err(e) => {
1071                    if let Some(inner_source) = e.source() {
1072                        println!("Caused by: {}", inner_source);
1073                    }
1074
1075                    error!("host get error: {}", e);
1076                    panic!("{}", e)
1077                }
1078            }
1079        }
1080    }
1081
1082    #[test]
1083    fn create_host_group_and_host() {
1084        init_logging();
1085
1086        if are_integration_tests_enabled() {
1087            let mut test_env = TestEnvBuilder::build();
1088
1089            let group_name = get_random_string();
1090            let host_name = get_random_string();
1091
1092            test_env.get_session()
1093                     .create_host_group(&group_name)
1094                     .create_host(&host_name);
1095
1096            assert!(test_env.latest_host_group_id > 0);
1097            assert!(test_env.latest_host_id > 0);
1098        }
1099    }
1100
1101    #[test]
1102    fn create_item() {
1103        init_logging();
1104
1105        if are_integration_tests_enabled() {
1106            let mut test_env = TestEnvBuilder::build();
1107
1108            let group_name = get_random_string();
1109            let host_name = get_random_string();
1110
1111            test_env.get_session()
1112                .create_host_group(&group_name)
1113                .create_host(&host_name);
1114
1115            let item_key = get_random_string();
1116            let item_name = get_random_string();
1117
1118            let request = CreateItemRequest {
1119                key_: item_key,
1120                name: item_name,
1121                host_id: test_env.latest_host_id.to_string(),
1122                r#type: 7,
1123                value_type: 4,
1124                interface_id: "0".to_string(),
1125                tags: vec![],
1126                delay: "30s".to_string(),
1127            };
1128
1129            match test_env.client.create_item(
1130                &test_env.session, &request
1131            ) {
1132                Ok(item_id) => {
1133                    assert!(item_id > 0);
1134                }
1135                Err(e) => {
1136                    if let Some(inner_source) = e.source() {
1137                        println!("Caused by: {}", inner_source);
1138                    }
1139
1140                    error!("item create error: {}", e);
1141                    panic!("{}", e)
1142                }
1143            }
1144        }
1145    }
1146
1147    #[test]
1148    fn create_trigger() {
1149        init_logging();
1150
1151        if are_integration_tests_enabled() {
1152            let mut test_env = TestEnvBuilder::build();
1153
1154            let group_name = get_random_string();
1155            let host_name = get_random_string();
1156
1157            let item_name = get_random_string();
1158            let item_key = format!("key{}", get_random_string());
1159
1160            test_env.get_session()
1161                    .create_host_group(&group_name)
1162                    .create_host(&host_name)
1163                    .create_item(&item_name, &item_key);
1164
1165            let trigger_description = get_random_string();
1166
1167            let expression = format!("last(/{host_name}/{item_key})=0");
1168
1169            let request = CreateTriggerRequest {
1170                description: trigger_description,
1171                expression: expression.to_string(),
1172                priority: 4,
1173                recovery_mode: Some(0),
1174                recovery_expression: None,
1175                url: None,
1176                event_name: None,
1177                dependencies: vec![],
1178                tags: vec![],
1179            };
1180
1181            match test_env.client.create_trigger(
1182                &test_env.session, &request
1183            ) {
1184                Ok(trigger_id) => assert!(trigger_id > 0),
1185                Err(e) => {
1186                    if let Some(inner_source) = e.source() {
1187                        println!("Caused by: {}", inner_source);
1188                    }
1189
1190                    error!("trigger create error: {}", e);
1191                    panic!("{}", e)
1192                }
1193            }
1194        }
1195    }
1196
1197    #[test]
1198    fn create_web_scenario() {
1199        init_logging();
1200
1201        if are_integration_tests_enabled() {
1202            let mut test_env = TestEnvBuilder::build();
1203
1204            let group_name = get_random_string();
1205            let host_name = get_random_string();
1206
1207            test_env.get_session()
1208                .create_host_group(&group_name)
1209                .create_host(&host_name);
1210
1211            let web_scenario_name = get_random_string();
1212
1213            let step = ZabbixWebScenarioStep {
1214                name: "Check github.com page".to_string(),
1215                url: "https://github.com".to_string(),
1216                status_codes: "200".to_string(),
1217                no: "0".to_string(),
1218            };
1219
1220            let request = CreateWebScenarioRequest {
1221                name: web_scenario_name,
1222                host_id: test_env.latest_host_id.to_string(),
1223                steps: vec![step],
1224            };
1225
1226            match test_env.client.create_webscenario(
1227                &test_env.session, &request
1228            ) {
1229                Ok(web_scenario_id) => {
1230                    assert!(web_scenario_id > 0);
1231                }
1232                Err(e) => {
1233                    if let Some(inner_source) = e.source() {
1234                        println!("Caused by: {}", inner_source);
1235                    }
1236
1237                    error!("web-scenario create error: {}", e);
1238                    panic!("{}", e)
1239                }
1240            }
1241        }
1242    }
1243}