use k8s_openapi::apimachinery::pkg::apis::meta::v1::{ListMeta, ObjectMeta};
use serde::{Deserialize, Serialize};
pub const ACCEPT_AGGREGATED_DISCOVERY_V2: &str = "application/json;g=apidiscovery.k8s.io;v=v2;as=APIGroupDiscoveryList,application/json;g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList,application/json";
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct APIGroupDiscoveryList {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<ListMeta>,
#[serde(default)]
pub items: Vec<APIGroupDiscovery>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct APIGroupDiscovery {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<ObjectMeta>,
#[serde(default)]
pub versions: Vec<APIVersionDiscovery>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct APIVersionDiscovery {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(default)]
pub resources: Vec<APIResourceDiscovery>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub freshness: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct APIResourceDiscovery {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub resource: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub response_kind: Option<GroupVersionKind>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub scope: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub singular_resource: Option<String>,
#[serde(default)]
pub verbs: Vec<String>,
#[serde(default)]
pub short_names: Vec<String>,
#[serde(default)]
pub categories: Vec<String>,
#[serde(default)]
pub subresources: Vec<APISubresourceDiscovery>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct APISubresourceDiscovery {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subresource: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub response_kind: Option<GroupVersionKind>,
#[serde(default)]
pub accepted_types: Vec<GroupVersionKind>,
#[serde(default)]
pub verbs: Vec<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GroupVersionKind {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deserialize_api_group_discovery_list() {
let json = r#"{
"kind": "APIGroupDiscoveryList",
"apiVersion": "apidiscovery.k8s.io/v2",
"metadata": {},
"items": [
{
"metadata": {
"name": "apps"
},
"versions": [
{
"version": "v1",
"freshness": "Current",
"resources": [
{
"resource": "deployments",
"responseKind": {
"group": "apps",
"version": "v1",
"kind": "Deployment"
},
"scope": "Namespaced",
"singularResource": "deployment",
"verbs": ["create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"],
"shortNames": ["deploy"],
"categories": ["all"],
"subresources": [
{
"subresource": "status",
"responseKind": {
"group": "apps",
"version": "v1",
"kind": "Deployment"
},
"verbs": ["get", "patch", "update"]
},
{
"subresource": "scale",
"responseKind": {
"group": "autoscaling",
"version": "v1",
"kind": "Scale"
},
"verbs": ["get", "patch", "update"]
}
]
}
]
}
]
}
]
}"#;
let result: APIGroupDiscoveryList = serde_json::from_str(json).unwrap();
assert_eq!(result.items.len(), 1);
let apps_group = &result.items[0];
assert_eq!(
apps_group.metadata.as_ref().and_then(|m| m.name.as_ref()),
Some(&"apps".to_string())
);
assert_eq!(apps_group.versions.len(), 1);
let v1 = &apps_group.versions[0];
assert_eq!(v1.version, Some("v1".to_string()));
assert_eq!(v1.freshness, Some("Current".to_string()));
assert_eq!(v1.resources.len(), 1);
let deployments = &v1.resources[0];
assert_eq!(deployments.resource, Some("deployments".to_string()));
assert_eq!(deployments.scope, Some("Namespaced".to_string()));
assert_eq!(deployments.singular_resource, Some("deployment".to_string()));
assert_eq!(deployments.short_names, vec!["deploy"]);
assert_eq!(deployments.categories, vec!["all"]);
assert!(deployments.verbs.contains(&"create".to_string()));
assert!(deployments.verbs.contains(&"watch".to_string()));
let response_kind = deployments.response_kind.as_ref().unwrap();
assert_eq!(response_kind.group, Some("apps".to_string()));
assert_eq!(response_kind.version, Some("v1".to_string()));
assert_eq!(response_kind.kind, Some("Deployment".to_string()));
assert_eq!(deployments.subresources.len(), 2);
let status_subresource = &deployments.subresources[0];
assert_eq!(status_subresource.subresource, Some("status".to_string()));
}
#[test]
fn deserialize_core_api_discovery() {
let json = r#"{
"kind": "APIGroupDiscoveryList",
"apiVersion": "apidiscovery.k8s.io/v2",
"metadata": {},
"items": [
{
"metadata": {
"name": ""
},
"versions": [
{
"version": "v1",
"freshness": "Current",
"resources": [
{
"resource": "pods",
"responseKind": {
"group": "",
"version": "v1",
"kind": "Pod"
},
"scope": "Namespaced",
"singularResource": "pod",
"verbs": ["create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"],
"shortNames": ["po"],
"categories": ["all"]
},
{
"resource": "namespaces",
"responseKind": {
"group": "",
"version": "v1",
"kind": "Namespace"
},
"scope": "Cluster",
"singularResource": "namespace",
"verbs": ["create", "delete", "get", "list", "patch", "update", "watch"],
"shortNames": ["ns"]
}
]
}
]
}
]
}"#;
let result: APIGroupDiscoveryList = serde_json::from_str(json).unwrap();
assert_eq!(result.items.len(), 1);
let core_group = &result.items[0];
assert_eq!(
core_group.metadata.as_ref().and_then(|m| m.name.as_ref()),
Some(&"".to_string())
);
let v1 = &core_group.versions[0];
assert_eq!(v1.resources.len(), 2);
let pods = &v1.resources[0];
assert_eq!(pods.resource, Some("pods".to_string()));
assert_eq!(pods.scope, Some("Namespaced".to_string()));
let namespaces = &v1.resources[1];
assert_eq!(namespaces.resource, Some("namespaces".to_string()));
assert_eq!(namespaces.scope, Some("Cluster".to_string()));
}
#[test]
fn serialize_roundtrip() {
let original = APIGroupDiscoveryList {
metadata: None,
items: vec![APIGroupDiscovery {
metadata: Some(ObjectMeta {
name: Some("test".to_string()),
..Default::default()
}),
versions: vec![APIVersionDiscovery {
version: Some("v1".to_string()),
freshness: Some("Current".to_string()),
resources: vec![],
}],
}],
};
let json = serde_json::to_string(&original).unwrap();
let deserialized: APIGroupDiscoveryList = serde_json::from_str(&json).unwrap();
assert_eq!(original, deserialized);
}
}