Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate GVK from ApiResource #495

Merged
merged 8 commits into from
May 15, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions examples/dynamic_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

use kube::{
api::{Api, DynamicObject, ResourceExt},
client::{Client, Discovery, Scope},
client::{
discovery::{verbs, Discovery, Scope},
Client,
},
};
use log::info;

Expand All @@ -23,7 +26,7 @@ async fn main() -> anyhow::Result<()> {
for group in discovery.groups() {
let ver = group.preferred_version_or_guess();
for (api_res, extras) in group.resources_by_version(ver) {
if !extras.operations.list {
if !extras.supports_operation(verbs::LIST) {
continue;
}
let api: Api<DynamicObject> = if extras.scope == Scope::Namespaced {
Expand Down
82 changes: 28 additions & 54 deletions kube/src/client/discovery.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! High-level utilities for runtime API discovery.

use crate::{api::ApiResource, Client};
use k8s_openapi::apimachinery::pkg::apis::meta::v1::APIResourceList;
use std::{cmp::Reverse, collections::HashMap};
Expand All @@ -11,45 +13,26 @@ pub enum Scope {
Namespaced,
}

/// Operations that are supported on the resource
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Operations {
/// Object can be created
pub create: bool,
/// Single object can be queried
pub get: bool,
/// Multiple objects can be queried
pub list: bool,
/// A watch can be started
pub watch: bool,
/// A single object can be deleted
pub delete: bool,
/// Multiple objects can be deleted
pub delete_collection: bool,
/// Object can be updated
pub update: bool,
/// Object can be patched
pub patch: bool,
/// All other verbs
pub other: Vec<String>,
/// Defines standard verbs
pub mod verbs {
/// Create a resource
pub const CREATE: &'static str = "create";
/// Get single resource
pub const GET: &'static str = "get";
/// List objects
pub const LIST: &'static str = "list";
/// Watch for objects changes
pub const WATCH: &'static str = "watch";
/// Delete single object
pub const DELETE: &'static str = "delete";
/// Delete multiple objects at once
pub const DELETE_COLLECTION: &'static str = "deletecollection";
/// Update an object
pub const UPDATE: &'static str = "update";
/// Patch an object
pub const PATCH: &'static str = "patch";
}

impl Operations {
/// Returns empty `Operations`
pub fn empty() -> Self {
Operations {
create: false,
get: false,
list: false,
watch: false,
delete: false,
delete_collection: false,
update: false,
patch: false,
other: Vec::new(),
}
}
}
/// Contains additional, detailed information abount API resource
#[derive(Debug, Clone)]
pub struct ApiResourceExtras {
Expand All @@ -61,7 +44,7 @@ pub struct ApiResourceExtras {
/// To work with subresources, use `Request` methods.
pub subresources: Vec<(ApiResource, ApiResourceExtras)>,
/// Supported operations on this resource
pub operations: Operations,
pub operations: Vec<String>,
}

impl ApiResourceExtras {
Expand All @@ -80,20 +63,6 @@ impl ApiResourceExtras {
} else {
Scope::Cluster
};
let mut operations = Operations::empty();
for verb in &ar.verbs {
match verb.as_str() {
"create" => operations.create = true,
"get" => operations.get = true,
"list" => operations.list = true,
"watch" => operations.watch = true,
"delete" => operations.delete = true,
"deletecollection" => operations.delete_collection = true,
"update" => operations.update = true,
"patch" => operations.patch = true,
_ => operations.other.push(verb.clone()),
}
}
let mut subresources = Vec::new();
let subresource_name_prefix = format!("{}/", name);
for res in &list.resources {
Expand All @@ -108,9 +77,14 @@ impl ApiResourceExtras {
ApiResourceExtras {
scope,
subresources,
operations,
operations: ar.verbs.clone(),
}
}

/// Checks that given verb is supported on this resource.
pub fn supports_operation(&self, operation: &str) -> bool {
self.operations.iter().any(|op| op == operation)
}
Copy link
Member

@clux clux Apr 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this is actually very nice.

I thought we would have

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Operations {
  Create,
  Get,
...
  Other(String),
}

but then your method avoids users needing to grab the verbs in scope if they wish (but they can still use the typed constants).

}

struct GroupVersionData {
Expand Down Expand Up @@ -148,7 +122,7 @@ pub struct Group {
preferred_version: Option<String>,
}

/// High-level utility for runtime API discovery.
/// Cached APIs information.
///
/// On creation `Discovery` queries Kubernetes API,
/// making list of all API resources, and provides a simple
Expand Down
4 changes: 1 addition & 3 deletions kube/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
//! This client can be used on its own or in conjuction with
//! the [`Api`][crate::api::Api] type for more structured
//! interaction with the kuberneres API.
mod discovery;

pub use discovery::{ApiResourceExtras, Discovery, Group, Operations, Scope};
pub mod discovery;

use crate::{api::WatchEvent, config::Config, error::ErrorResponse, service::Service, Error, Result};

Expand Down