Skip to content

Commit 03caece

Browse files
committed
chore: Version S3 CRDs
1 parent d896dd2 commit 03caece

File tree

3 files changed

+140
-124
lines changed

3 files changed

+140
-124
lines changed

crates/stackable-operator/src/crd/s3/bucket.rs

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ use kube::CustomResource;
22
use schemars::JsonSchema;
33
use serde::{Deserialize, Serialize};
44
use snafu::{ResultExt as _, Snafu};
5+
use stackable_versioned::versioned;
56

6-
use crate::{
7-
client::Client,
8-
crd::s3::{ConnectionError, ConnectionInlineOrReference, ConnectionSpec},
9-
};
7+
use crate::{client::Client, crd::s3::ConnectionError};
108

119
#[derive(Debug, Snafu)]
1210
pub enum BucketError {
@@ -20,50 +18,61 @@ pub enum BucketError {
2018
ResolveConnection { source: ConnectionError },
2119
}
2220

23-
/// S3 bucket specification containing the bucket name and an inlined or referenced connection specification.
24-
/// Learn more on the [S3 concept documentation](DOCS_BASE_URL_PLACEHOLDER/concepts/s3).
25-
#[derive(Clone, CustomResource, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
26-
#[kube(
27-
group = "s3.stackable.tech",
28-
version = "v1alpha1",
29-
kind = "S3Bucket",
30-
plural = "s3buckets",
31-
crates(
32-
kube_core = "kube::core",
33-
k8s_openapi = "k8s_openapi",
34-
schemars = "schemars"
35-
),
36-
namespaced
37-
)]
38-
#[serde(rename_all = "camelCase")]
39-
pub struct BucketSpec {
40-
/// The name of the S3 bucket.
41-
pub bucket_name: String,
21+
#[versioned(version(name = "v1alpha1"))]
22+
pub mod versioned {
23+
// This makes it possible to refer to S3 connection related structs and enums
24+
// by v1alpha1.
25+
// NOTE (@Techassi): However, this will break once items defined in here will
26+
// reference each other by v1alpha1. One possible solution is to import
27+
// connection::v1alpha1 as v1alpha1_conn or similar.
28+
mod v1alpha1 {
29+
use crate::crd::s3::connection::v1alpha1;
30+
}
4231

43-
/// The definition of an S3 connection, either inline or as a reference.
44-
pub connection: ConnectionInlineOrReference,
45-
}
32+
/// S3 bucket specification containing the bucket name and an inlined or referenced connection specification.
33+
/// Learn more on the [S3 concept documentation](DOCS_BASE_URL_PLACEHOLDER/concepts/s3).
34+
#[versioned(k8s(
35+
group = "s3.stackable.tech",
36+
kind = "S3Bucket",
37+
plural = "s3buckets",
38+
crates(
39+
kube_core = "kube::core",
40+
k8s_openapi = "k8s_openapi",
41+
schemars = "schemars"
42+
),
43+
namespaced
44+
))]
45+
#[derive(Clone, CustomResource, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
46+
#[serde(rename_all = "camelCase")]
47+
pub struct BucketSpec {
48+
/// The name of the S3 bucket.
49+
pub bucket_name: String,
4650

47-
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
48-
#[serde(rename_all = "camelCase")]
49-
// TODO: This probably should be serde(untagged), but this would be a breaking change
50-
pub enum BucketInlineOrReference {
51-
Inline(BucketSpec),
52-
Reference(String),
53-
}
51+
/// The definition of an S3 connection, either inline or as a reference.
52+
pub connection: v1alpha1::InlineConnectionOrReference,
53+
}
5454

55-
/// Use this struct in your operator.
56-
pub struct ResolvedBucket {
57-
pub bucket_name: String,
58-
pub connection: ConnectionSpec,
55+
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
56+
#[serde(rename_all = "camelCase")]
57+
// TODO: This probably should be serde(untagged), but this would be a breaking change
58+
pub enum InlineBucketOrReference {
59+
Inline(BucketSpec),
60+
Reference(String),
61+
}
62+
63+
/// Use this struct in your operator.
64+
pub struct ResolvedBucket {
65+
pub bucket_name: String,
66+
pub connection: v1alpha1::ConnectionSpec,
67+
}
5968
}
6069

61-
impl BucketInlineOrReference {
70+
impl v1alpha1::InlineBucketOrReference {
6271
pub async fn resolve(
6372
self,
6473
client: &Client,
6574
namespace: &str,
66-
) -> Result<ResolvedBucket, BucketError> {
75+
) -> Result<v1alpha1::ResolvedBucket, BucketError> {
6776
match self {
6877
Self::Inline(inline) => {
6978
let connection = inline
@@ -72,14 +81,14 @@ impl BucketInlineOrReference {
7281
.await
7382
.context(ResolveConnectionSnafu)?;
7483

75-
Ok(ResolvedBucket {
84+
Ok(v1alpha1::ResolvedBucket {
7685
bucket_name: inline.bucket_name,
7786
connection,
7887
})
7988
}
8089
Self::Reference(reference) => {
8190
let bucket_spec = client
82-
.get::<S3Bucket>(&reference, namespace)
91+
.get::<v1alpha1::S3Bucket>(&reference, namespace)
8392
.await
8493
.context(RetrieveS3ConnectionSnafu {
8594
s3_connection: reference,
@@ -92,7 +101,7 @@ impl BucketInlineOrReference {
92101
.await
93102
.context(ResolveConnectionSnafu)?;
94103

95-
Ok(ResolvedBucket {
104+
Ok(v1alpha1::ResolvedBucket {
96105
bucket_name: bucket_spec.bucket_name,
97106
connection,
98107
})

crates/stackable-operator/src/crd/s3/connection.rs

Lines changed: 83 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use kube::CustomResource;
22
use schemars::JsonSchema;
33
use serde::{Deserialize, Serialize};
44
use snafu::{ResultExt as _, Snafu};
5+
use stackable_versioned::versioned;
56
use url::Url;
67

78
use crate::{
@@ -48,78 +49,88 @@ pub enum ConnectionError {
4849
},
4950
}
5051

51-
/// S3 connection definition as a resource.
52-
/// Learn more on the [S3 concept documentation](DOCS_BASE_URL_PLACEHOLDER/concepts/s3).
53-
#[derive(CustomResource, Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
54-
#[kube(
55-
group = "s3.stackable.tech",
56-
version = "v1alpha1",
57-
kind = "S3Connection",
58-
plural = "s3connections",
59-
crates(
60-
kube_core = "kube::core",
61-
k8s_openapi = "k8s_openapi",
62-
schemars = "schemars"
63-
),
64-
namespaced
65-
)]
66-
#[serde(rename_all = "camelCase")]
67-
pub struct ConnectionSpec {
68-
/// Host of the S3 server without any protocol or port. For example: `west1.my-cloud.com`.
69-
pub host: HostName,
70-
71-
/// Port the S3 server listens on.
72-
/// If not specified the product will determine the port to use.
73-
#[serde(default, skip_serializing_if = "Option::is_none")]
74-
pub port: Option<u16>,
75-
76-
/// Bucket region used for signing headers (sigv4).
77-
///
78-
/// This defaults to `us-east-1` which is compatible with other implementations such as Minio.
79-
///
80-
/// WARNING: Some products use the Hadoop S3 implementation which falls back to us-east-2.
81-
#[serde(default)]
82-
pub region: Region,
83-
84-
/// Which access style to use.
85-
/// Defaults to virtual hosted-style as most of the data products out there.
86-
/// Have a look at the [AWS documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html).
87-
#[serde(default)]
88-
pub access_style: S3AccessStyle,
89-
90-
/// If the S3 uses authentication you have to specify you S3 credentials.
91-
/// In the most cases a [SecretClass](DOCS_BASE_URL_PLACEHOLDER/secret-operator/secretclass)
92-
/// providing `accessKey` and `secretKey` is sufficient.
93-
#[serde(default, skip_serializing_if = "Option::is_none")]
94-
pub credentials: Option<SecretClassVolume>,
95-
96-
/// Use a TLS connection. If not specified no TLS will be used.
97-
#[serde(flatten)]
98-
pub tls: TlsClientDetails,
99-
}
52+
#[versioned(version(name = "v1alpha1"))]
53+
pub mod versioned {
54+
/// S3 connection definition as a resource.
55+
/// Learn more on the [S3 concept documentation](DOCS_BASE_URL_PLACEHOLDER/concepts/s3).
56+
#[versioned(k8s(
57+
group = "s3.stackable.tech",
58+
kind = "S3Connection",
59+
plural = "s3connections",
60+
crates(
61+
kube_core = "kube::core",
62+
k8s_openapi = "k8s_openapi",
63+
schemars = "schemars"
64+
),
65+
namespaced
66+
))]
67+
#[derive(CustomResource, Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
68+
#[serde(rename_all = "camelCase")]
69+
pub struct ConnectionSpec {
70+
/// Host of the S3 server without any protocol or port. For example: `west1.my-cloud.com`.
71+
pub host: HostName,
72+
73+
/// Port the S3 server listens on.
74+
/// If not specified the product will determine the port to use.
75+
#[serde(default, skip_serializing_if = "Option::is_none")]
76+
pub port: Option<u16>,
77+
78+
/// Bucket region used for signing headers (sigv4).
79+
///
80+
/// This defaults to `us-east-1` which is compatible with other implementations such as Minio.
81+
///
82+
/// WARNING: Some products use the Hadoop S3 implementation which falls back to us-east-2.
83+
#[serde(default)]
84+
pub region: Region,
85+
86+
/// Which access style to use.
87+
/// Defaults to virtual hosted-style as most of the data products out there.
88+
/// Have a look at the [AWS documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html).
89+
#[serde(default)]
90+
pub access_style: S3AccessStyle,
91+
92+
/// If the S3 uses authentication you have to specify you S3 credentials.
93+
/// In the most cases a [SecretClass](DOCS_BASE_URL_PLACEHOLDER/secret-operator/secretclass)
94+
/// providing `accessKey` and `secretKey` is sufficient.
95+
#[serde(default, skip_serializing_if = "Option::is_none")]
96+
pub credentials: Option<SecretClassVolume>,
97+
98+
/// Use a TLS connection. If not specified no TLS will be used.
99+
#[serde(flatten)]
100+
pub tls: TlsClientDetails,
101+
}
100102

101-
#[derive(
102-
strum::Display, Clone, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize,
103-
)]
104-
#[strum(serialize_all = "PascalCase")]
105-
pub enum S3AccessStyle {
106-
/// Use path-style access as described in <https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access>
107-
Path,
108-
109-
/// Use as virtual hosted-style access as described in <https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#virtual-hosted-style-access>
110-
#[default]
111-
VirtualHosted,
112-
}
103+
#[derive(
104+
strum::Display, Clone, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize,
105+
)]
106+
#[strum(serialize_all = "PascalCase")]
107+
pub enum S3AccessStyle {
108+
/// Use path-style access as described in <https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access>
109+
Path,
110+
111+
/// Use as virtual hosted-style access as described in <https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#virtual-hosted-style-access>
112+
#[default]
113+
VirtualHosted,
114+
}
113115

114-
/// Set a named S3 Bucket region.
115-
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
116-
#[serde(rename_all = "camelCase")]
117-
pub struct Region {
118-
#[serde(default = "Region::default_region_name")]
119-
pub name: String,
116+
/// Set a named S3 Bucket region.
117+
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
118+
#[serde(rename_all = "camelCase")]
119+
pub struct Region {
120+
#[serde(default = "v1alpha1::Region::default_region_name")]
121+
pub name: String,
122+
}
123+
124+
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
125+
#[serde(rename_all = "camelCase")]
126+
// TODO: This probably should be serde(untagged), but this would be a breaking change
127+
pub enum InlineConnectionOrReference {
128+
Inline(ConnectionSpec),
129+
Reference(String),
130+
}
120131
}
121132

122-
impl Region {
133+
impl v1alpha1::Region {
123134
/// Having it as `const &str` as well, so we don't always allocate a [`String`] just for comparisons
124135
pub const DEFAULT_REGION_NAME: &str = "us-east-1";
125136

@@ -137,26 +148,18 @@ impl Region {
137148
}
138149
}
139150

140-
impl Default for Region {
151+
impl Default for v1alpha1::Region {
141152
fn default() -> Self {
142153
Self {
143154
name: Self::default_region_name(),
144155
}
145156
}
146157
}
147158

148-
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
149-
#[serde(rename_all = "camelCase")]
150-
// TODO: This probably should be serde(untagged), but this would be a breaking change
151-
pub enum ConnectionInlineOrReference {
152-
Inline(ConnectionSpec),
153-
Reference(String),
154-
}
155-
156159
/// Use this type in you operator!
157-
pub type ResolvedConnection = ConnectionSpec;
160+
pub type ResolvedConnection = v1alpha1::ConnectionSpec;
158161

159-
impl ConnectionInlineOrReference {
162+
impl v1alpha1::InlineConnectionOrReference {
160163
pub async fn resolve(
161164
self,
162165
client: &Client,
@@ -166,7 +169,7 @@ impl ConnectionInlineOrReference {
166169
Self::Inline(inline) => Ok(inline),
167170
Self::Reference(reference) => {
168171
let connection_spec = client
169-
.get::<S3Connection>(&reference, namespace)
172+
.get::<v1alpha1::S3Connection>(&reference, namespace)
170173
.await
171174
.context(RetrieveS3ConnectionSnafu {
172175
s3_connection: reference,
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
mod bucket;
22
mod connection;
33

4-
pub use bucket::*;
5-
pub use connection::*;
4+
pub use connection::ConnectionError;
5+
6+
// Group all v1alpha1 items in one module
7+
pub mod v1alpha1 {
8+
pub use super::{bucket::v1alpha1::*, connection::v1alpha1::*};
9+
}

0 commit comments

Comments
 (0)