Skip to content

Commit 5397e00

Browse files
committed
1 parent 65da370 commit 5397e00

File tree

3 files changed

+71
-47
lines changed

3 files changed

+71
-47
lines changed

examples/crd_api.rs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
#[macro_use] extern crate log;
22
#[macro_use] extern crate failure;
33
#[macro_use] extern crate serde_derive;
4+
use serde_json::json;
45

56
use kube::{
6-
api::{Api, PostResponse, CreateResponse, PostParams, Object, Void},
7+
api::{Api, PostResponse, PostParams, Object},
78
client::APIClient,
89
config,
910
};
1011

12+
//use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta;
1113
use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1beta1::{
1214
//CustomResourceDefinition as Crd,
1315
CustomResourceDefinitionSpec as CrdSpec,
14-
CustomResourceDefinitionNames as CrdNames,
1516
CustomResourceDefinitionStatus as CrdStatus,
1617
};
1718

@@ -37,35 +38,46 @@ fn main() -> Result<(), failure::Error> {
3738
let crds = Api::v1beta1CustomResourceDefinition();
3839

3940
// Create the CRD so we can create Foos in kube
40-
let foocrd = CrdSpec {
41-
group: "clux.dev".into(),
42-
version: Some("v1".into()),
43-
scope: "Namespaced".into(),
44-
names: CrdNames {
45-
plural: "foos".into(),
46-
singular: Some("foo".into()),
47-
kind: "Foo".into(),
48-
..Default::default()
41+
let foocrd = json!({
42+
"metadata": {
43+
"name": "foos.clux.dev"
4944
},
50-
..Default::default()
51-
};
45+
"spec": {
46+
"group": "clux.dev",
47+
"version": "v1",
48+
"scope": "Namespaced",
49+
"names": {
50+
"plural": "foos",
51+
"singular": "foo",
52+
"kind": "Foo",
53+
}
54+
}
55+
});
56+
5257
let pp = PostParams::default();
5358
let req = crds.create(&pp, serde_json::to_vec(&foocrd)?)?;
54-
match client.request::<CreateResponse<Object<CrdSpec, CrdStatus>>>(req)? {
55-
CreateResponse::Created(o) => info!("Created {}", o.metadata.name),
56-
CreateResponse::Accepted(o) => info!("Accepted {}", o.metadata.name),
57-
CreateResponse::Ok(o) => info!("Ok {}", o.metadata.name),
58-
CreateResponse::Error => bail!("Uh oh"),
59+
if let Ok(res) = client.request::<Object<CrdSpec, CrdStatus>>(req) {
60+
info!("Created {}", res.metadata.name);
61+
debug!("Created CRD: {:?}", res.spec);
62+
} else {
63+
// TODO: need error code here for ease
5964
}
6065

66+
6167
// Manage the Foo CR
6268
let foos = Api::customResource("foos.clux.dev").version("v1");
6369

6470
// Create some Foos
65-
let f1 = FooSpec { name: "baz".into(), info: "unpatched baz".into() };
71+
let f1 = json!({
72+
"metadata": { "name": "baz" },
73+
"spec": FooSpec { name: "baz".into(), info: "unpatched baz".into() }
74+
});
6675
foos.create(&pp, serde_json::to_vec(&f1)?)?;
6776

68-
let f2 = FooSpec { name: "qux".into(), info: "unpatched qux".into() };
77+
let f2 = json!({
78+
"metadata": { "name": "qux" },
79+
"spec": FooSpec { name: "qux".into(), info: "unpatched qux".into() }
80+
});
6981
foos.create(&pp, serde_json::to_vec(&f2)?)?;
7082

7183

@@ -81,11 +93,9 @@ fn main() -> Result<(), failure::Error> {
8193
// Set its status:
8294
let fs = FooStatus { is_bad: true };
8395
let req = foos.replace_status("baz", &pp, serde_json::to_vec(&fs)?)?;
84-
match client.request::<PostResponse<Foo>>(req)? {
85-
PostResponse::Ok(o) => info!("Replaced status {:?} for {}", o.status, o.metadata.name),
86-
PostResponse::Created(o) => info!("Replaced status {:?} for {}", o.status, o.metadata.name),
87-
PostResponse::Error => bail!("uh oh 2"),
88-
}
96+
let res = client.request::<Foo>(req)?;
97+
info!("Replaced status {:?} for {}", res.status, res.metadata.name);
98+
8999

90100
// Verify we can get it
91101
let req = foos.get("baz")?;
@@ -97,6 +107,5 @@ fn main() -> Result<(), failure::Error> {
97107
let f2 = client.request::<Foo>(req)?;
98108
assert_eq!(f2.spec.info, "unpatched qux");
99109

100-
101110
Ok(())
102111
}

src/api/api.rs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{Result, Error};
66
///
77
/// Used to construct requests from url conventions.
88
/// When data is PUT/POST/PATCH'd this struct requires raw bytes.
9-
#[derive(Clone)]
9+
#[derive(Clone, Debug)]
1010
pub struct Api {
1111
/// API Resource name
1212
pub resource: String,
@@ -16,6 +16,8 @@ pub struct Api {
1616
pub namespace: Option<String>,
1717
/// API version of the resource
1818
pub version: String,
19+
/// Subresource version of scale (takes precedence)
20+
pub scale_version: String,
1921
/// Name of the api prefix (api or apis typically)
2022
pub prefix: String,
2123

@@ -28,18 +30,12 @@ impl Default for Api {
2830
namespace: None,
2931
group: "".into(),
3032
version: "v1".into(),
33+
scale_version: "v1beta2".into(), // not stable yet
3134
prefix: "apis".into(), // seems most common
3235
}
3336
}
3437
}
3538

36-
impl Debug for Api {
37-
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
38-
write!(f, "Api {{ {} {} {} {} {:?} }}", self.resource, self.version,
39-
self.group, self.prefix, self.namespace)
40-
}
41-
}
42-
4339
#[allow(non_snake_case)]
4440
impl Api {
4541
pub fn within(mut self, ns: &str) -> Self {
@@ -142,14 +138,30 @@ impl Api {
142138

143139
// -------------------------------------------------------
144140

141+
// TODO: set these..
142+
enum SubResource {
143+
Scale,
144+
Status,
145+
}
146+
impl SubResource {
147+
fn version(&self) -> String {
148+
match self {
149+
SubResource::Scale => "v1beta2".into(),
150+
SubResource::Status => "v1beta2".into(),
151+
}
152+
}
153+
}
145154

146-
impl ToString for Api
147-
{
148-
fn to_string(&self) -> String {
155+
impl Api {
156+
fn make_url(&self, sub: Option<SubResource>) -> String {
149157
let pref = if self.prefix == "" { "".into() } else { format!("{}/", self.prefix) };
150158
let g = if self.group == "" { "".into() } else { format!("{}/", self.group) };
151-
let v = if self.version == "" { "".into() } else { format!("{}/", self.version) };
159+
let v = match sub {
160+
Some(s) => format!("{}/", s.version()),
161+
None => format!("{}/", self.version)
162+
};
152163
let n = if let Some(ns) = &self.namespace { format!("namespaces/{}/", ns) } else { "".into() };
164+
153165
format!("/{prefix}{group}{version}{namespaces}{resource}",
154166
prefix = pref,
155167
group = g,
@@ -181,7 +193,7 @@ pub struct PostParams {
181193
impl Api {
182194
/// Create a list request to fully re-fetch the state
183195
pub fn list(&self, par: &GetParams) -> Result<http::Request<Vec<u8>>> {
184-
let mut qp = url::form_urlencoded::Serializer::new(self.to_string() + "?");
196+
let mut qp = url::form_urlencoded::Serializer::new(self.make_url(None) + "?");
185197

186198
if let Some(fields) = &par.field_selector {
187199
qp.append_pair("fieldSelector", &fields);
@@ -200,7 +212,7 @@ impl Api {
200212

201213
/// Create a minimial list request to seed an initial resourceVersion
202214
pub(crate) fn list_zero_resource_entries(&self, par: &GetParams) -> Result<http::Request<Vec<u8>>> {
203-
let mut qp = url::form_urlencoded::Serializer::new(self.to_string() + "?");
215+
let mut qp = url::form_urlencoded::Serializer::new(self.make_url(None) + "?");
204216
qp.append_pair("limit", "1"); // can't have 0..
205217
if par.include_uninitialized {
206218
qp.append_pair("includeUninitialized", "true");
@@ -213,7 +225,7 @@ impl Api {
213225

214226
/// Create watch request for a Api at a given version
215227
pub(crate) fn watch(&self, par: &GetParams, ver: &str) -> Result<http::Request<Vec<u8>>> {
216-
let mut qp = url::form_urlencoded::Serializer::new(self.to_string() + "?");
228+
let mut qp = url::form_urlencoded::Serializer::new(self.make_url(None) + "?");
217229

218230
qp.append_pair("watch", "true");
219231
qp.append_pair("resourceVersion", ver);
@@ -236,14 +248,14 @@ impl Api {
236248

237249
/// Get a single instance
238250
pub fn get(&self, name: &str) -> Result<http::Request<Vec<u8>>> {
239-
let mut qp = url::form_urlencoded::Serializer::new(self.to_string() + "/" + name);
251+
let mut qp = url::form_urlencoded::Serializer::new(self.make_url(None) + "/" + name);
240252
let urlstr = qp.finish();
241253
let mut req = http::Request::get(urlstr);
242254
req.body(vec![]).map_err(Error::from)
243255
}
244256

245257
pub fn create(&self, pp: &PostParams, data: Vec<u8>) -> Result<http::Request<Vec<u8>>> {
246-
let mut qp = url::form_urlencoded::Serializer::new(self.to_string() + "?");
258+
let mut qp = url::form_urlencoded::Serializer::new(self.make_url(None) + "?");
247259
if pp.dry_run {
248260
qp.append_pair("dryRun", "true");
249261
}
@@ -252,7 +264,7 @@ impl Api {
252264
req.body(data).map_err(Error::from)
253265
}
254266
pub fn replace(&self, name: &str, pp: &PostParams, data: Vec<u8>) -> Result<http::Request<Vec<u8>>> {
255-
let base_url = self.to_string() + "/" + name + "?";
267+
let base_url = self.make_url(None) + "/" + name + "?";
256268
let mut qp = url::form_urlencoded::Serializer::new(base_url);
257269
if pp.dry_run {
258270
qp.append_pair("dryRun", "true");
@@ -282,7 +294,7 @@ impl Api {
282294
//}
283295

284296
pub fn patch_status(&self, name: &str, pp: &PostParams, patch: Vec<u8>) -> Result<http::Request<Vec<u8>>> {
285-
let base_url = self.to_string() + "/" + name + "/status";
297+
let base_url = self.make_url(Some(SubResource::Status)) + "/" + name + "/status";
286298
let mut qp = url::form_urlencoded::Serializer::new(base_url);
287299
if pp.dry_run {
288300
qp.append_pair("dryRun", "true");
@@ -293,7 +305,7 @@ impl Api {
293305
}
294306

295307
pub fn replace_status(&self, name: &str, pp: &PostParams, data: Vec<u8>) -> Result<http::Request<Vec<u8>>> {
296-
let base_url = self.to_string() + "/" + name + "/status";
308+
let base_url = self.make_url(Some(SubResource::Status)) + "/" + name + "/status";
297309
let mut qp = url::form_urlencoded::Serializer::new(base_url);
298310
if pp.dry_run {
299311
qp.append_pair("dryRun", "true");
@@ -348,7 +360,7 @@ fn patch_status_path(){
348360
let r = Api::v1Node();
349361
let pp = PostParams::default();
350362
let req = r.patch_status("mynode", &pp, vec![]).unwrap();
351-
assert_eq!(req.uri(), "/api/v1/nodes/mynode/status");
363+
assert_eq!(req.uri(), "/api/v1beta2/nodes/mynode/status");
352364
assert_eq!(req.method(), "PATCH");
353365
}
354366
#[test]

src/api/resource.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ pub enum PostResponse<T> where
144144
Error, // Unauthorized or other
145145
}
146146

147+
147148
/// Generic post response object
148149
///
149150
/// Returned from create new
@@ -156,6 +157,8 @@ pub enum CreateResponse<T> where
156157
Accepted(T), // StatusCode::ACCEPTED
157158
Error, // Unauthorized or other
158159
}
160+
// NB: 409 CONFLICT returned when already exists..
161+
159162

160163
/// Generic response object
161164
///

0 commit comments

Comments
 (0)