• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kdash-rs / kdash / 3750513782

pending completion
3750513782

push

github

Deepu
fix tests

982 of 4441 branches covered (22.11%)

Branch coverage included in aggregate %.

2731 of 4724 relevant lines covered (57.81%)

8.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.12
/src/app/svcs.rs
1
use k8s_openapi::{
2
  api::core::v1::{Service, ServicePort},
3
  chrono::Utc,
4
};
5

6
use super::{
7
  models::KubeResource,
8
  utils::{self, UNKNOWN},
9
};
10

11
#[derive(Clone, Debug, PartialEq)]
10✔
12
pub struct KubeSvc {
13
  pub namespace: String,
5✔
14
  pub name: String,
5!
15
  pub type_: String,
5!
16
  pub cluster_ip: String,
5!
17
  pub external_ip: String,
5!
18
  pub ports: String,
5!
19
  pub age: String,
5!
20
  k8s_obj: Service,
5!
21
}
22

23
impl From<Service> for KubeSvc {
24
  fn from(service: Service) -> Self {
5✔
25
    let (type_, cluster_ip, external_ip, ports) = match &service.spec {
10!
26
      Some(spec) => {
5✔
27
        let type_ = match &spec.type_ {
5!
28
          Some(type_) => type_.clone(),
5✔
29
          _ => UNKNOWN.into(),
×
30
        };
31

32
        let external_ips = match type_.as_str() {
5✔
33
          "ClusterIP" | "NodePort" => spec.external_ips.clone(),
5!
34
          "LoadBalancer" => get_lb_ext_ips(&service, spec.external_ips.clone()),
1!
35
          "ExternalName" => Some(vec![spec.external_name.clone().unwrap_or_default()]),
×
36
          _ => None,
×
37
        };
38

39
        (
5✔
40
          type_,
5✔
41
          spec.cluster_ip.as_ref().unwrap_or(&"None".into()).clone(),
5✔
42
          external_ips.unwrap_or_default().join(","),
5✔
43
          get_ports(&spec.ports).unwrap_or_default(),
5✔
44
        )
45
      }
5✔
46
      _ => (
×
47
        UNKNOWN.into(),
×
48
        String::default(),
×
49
        String::default(),
×
50
        String::default(),
×
51
      ),
×
52
    };
53

54
    KubeSvc {
5✔
55
      name: service.metadata.name.clone().unwrap_or_default(),
5✔
56
      type_,
5✔
57
      namespace: service.metadata.namespace.clone().unwrap_or_default(),
5✔
58
      cluster_ip,
5✔
59
      external_ip,
5✔
60
      ports,
5✔
61
      age: utils::to_age(service.metadata.creation_timestamp.as_ref(), Utc::now()),
5✔
62
      k8s_obj: utils::sanitize_obj(service),
5✔
63
    }
64
  }
5✔
65
}
66

67
impl KubeResource<Service> for KubeSvc {
68
  fn get_k8s_obj(&self) -> &Service {
×
69
    &self.k8s_obj
70
  }
×
71
}
72

73
fn get_ports(s_ports: &Option<Vec<ServicePort>>) -> Option<String> {
5✔
74
  s_ports.as_ref().map(|ports| {
10✔
75
    ports
5✔
76
      .iter()
77
      .map(|s_port| {
8✔
78
        let mut port = String::new();
8✔
79
        if let Some(name) = s_port.name.clone() {
8✔
80
          port = format!("{}:", name);
7✔
81
        }
8!
82
        port = format!("{}{}►{}", port, s_port.port, s_port.node_port.unwrap_or(0));
8✔
83
        if let Some(protocol) = s_port.protocol.clone() {
8!
84
          if protocol != "TCP" {
8✔
85
            port = format!("{}/{}", port, s_port.protocol.clone().unwrap());
1✔
86
          }
87
        }
8!
88
        port
89
      })
8✔
90
      .collect::<Vec<_>>()
91
      .join(" ")
92
  })
5✔
93
}
5✔
94

95
fn get_lb_ext_ips(service: &Service, external_ips: Option<Vec<String>>) -> Option<Vec<String>> {
1✔
96
  let mut lb_ips = match &service.status {
1!
97
    Some(ss) => match &ss.load_balancer {
1!
98
      Some(lb) => {
1✔
99
        let ing = &lb.ingress;
1✔
100
        ing
1✔
101
          .clone()
102
          .unwrap_or_default()
103
          .iter()
104
          .map(|lb_ing| {
1✔
105
            if lb_ing.ip.is_some() {
1!
106
              lb_ing.ip.clone().unwrap_or_default()
1✔
107
            } else if lb_ing.hostname.is_some() {
×
108
              lb_ing.hostname.clone().unwrap_or_default()
×
109
            } else {
110
              String::default()
×
111
            }
112
          })
1✔
113
          .collect::<Vec<String>>()
1✔
114
      }
1✔
115
      None => vec![],
×
116
    },
117
    None => vec![],
×
118
  };
119
  if external_ips.is_none() && !lb_ips.is_empty() {
1!
120
    lb_ips.extend(external_ips.unwrap_or_default());
1✔
121
    Some(lb_ips)
1✔
122
  } else if !lb_ips.is_empty() {
×
123
    Some(lb_ips)
×
124
  } else {
125
    Some(vec!["<pending>".into()])
×
126
  }
127
}
1!
128

129
#[cfg(test)]
130
mod tests {
131
  use super::*;
132
  use crate::app::test_utils::*;
133

134
  #[test]
135
  fn test_services_from_api() {
2✔
136
    let (svcs, svc_list): (Vec<KubeSvc>, Vec<_>) = convert_resource_from_file("svcs");
1✔
137

138
    assert_eq!(svcs.len(), 5);
1!
139
    assert_eq!(
1✔
140
      svcs[0],
1✔
141
      KubeSvc {
1✔
142
        name: "kubernetes".into(),
1✔
143
        namespace: "default".into(),
1✔
144
        age: utils::to_age(Some(&get_time("2021-05-10T21:48:03Z")), Utc::now()),
1✔
145
        k8s_obj: svc_list[0].clone(),
1✔
146
        type_: "ClusterIP".into(),
1✔
147
        cluster_ip: "10.43.0.1".into(),
1✔
148
        external_ip: "".into(),
1✔
149
        ports: "https:443►0".into(),
1!
150
      }
151
    );
152
    assert_eq!(
1✔
153
      svcs[1],
1✔
154
      KubeSvc {
1✔
155
        name: "kube-dns".into(),
1✔
156
        namespace: "kube-system".into(),
1✔
157
        age: utils::to_age(Some(&get_time("2021-05-10T21:48:03Z")), Utc::now()),
1✔
158
        k8s_obj: svc_list[1].clone(),
1✔
159
        type_: "ClusterIP".into(),
1✔
160
        cluster_ip: "10.43.0.10".into(),
1✔
161
        external_ip: "".into(),
1✔
162
        ports: "dns:53►0/UDP dns-tcp:53►0 metrics:9153►0".into(),
1!
163
      }
164
    );
165
    assert_eq!(
1✔
166
      svcs[2],
1✔
167
      KubeSvc {
1✔
168
        name: "metrics-server".into(),
1✔
169
        namespace: "kube-system".into(),
1✔
170
        age: utils::to_age(Some(&get_time("2021-05-10T21:48:03Z")), Utc::now()),
1✔
171
        k8s_obj: svc_list[2].clone(),
1✔
172
        type_: "ClusterIP".into(),
1✔
173
        cluster_ip: "10.43.93.186".into(),
1✔
174
        external_ip: "".into(),
1✔
175
        ports: "443►0".into(),
1!
176
      }
177
    );
178
    assert_eq!(
1✔
179
      svcs[3],
1✔
180
      KubeSvc {
1✔
181
        name: "traefik-prometheus".into(),
1✔
182
        namespace: "kube-system".into(),
1✔
183
        age: utils::to_age(Some(&get_time("2021-05-10T21:48:35Z")), Utc::now()),
1✔
184
        k8s_obj: svc_list[3].clone(),
1✔
185
        type_: "ClusterIP".into(),
1✔
186
        cluster_ip: "10.43.9.106".into(),
1✔
187
        external_ip: "".into(),
1✔
188
        ports: "metrics:9100►0".into(),
1!
189
      }
190
    );
191
    assert_eq!(
1✔
192
      svcs[4],
1✔
193
      KubeSvc {
1✔
194
        name: "traefik".into(),
1✔
195
        namespace: "kube-system".into(),
1✔
196
        age: utils::to_age(Some(&get_time("2021-05-10T21:48:35Z")), Utc::now()),
1✔
197
        k8s_obj: svc_list[4].clone(),
1✔
198
        type_: "LoadBalancer".into(),
1✔
199
        cluster_ip: "10.43.235.227".into(),
1✔
200
        external_ip: "172.20.0.2".into(),
1✔
201
        ports: "http:80►30723 https:443►31954".into(),
1!
202
      }
203
    );
204
  }
2✔
205
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc