Skip to content

Commit

Permalink
feat: initial add of volume support (oam-dev#257)
Browse files Browse the repository at this point in the history
* feat: initial add of volume support

Signed-off-by: Matt Butcher <[email protected]>

* renamed local variable to be less confusing.
  • Loading branch information
technosophos authored Oct 3, 2019
1 parent ab688e1 commit fac50ce
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 36 deletions.
27 changes: 27 additions & 0 deletions examples/volumes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# This is a stand-alone example of using a volume with a component.
apiVersion: core.hydra.io/v1alpha1
kind: ComponentSchematic
metadata:
name: server-with-volume
spec:
workloadType: core.hydra.io/v1alpha1.Server
containers:
- name: server
image: nginx:latest
resources:
volumes:
- name: myvol
mountPath: /myvol
disk:
required: "200M"
ephemeral: true
---
apiVersion: core.hydra.io/v1alpha1
kind: ApplicationConfiguration
metadata:
name: example-server-with-volume
spec:
components:
- name: server-with-volume
instanceName: example-server-with-volume
# TODO: Add trait to bind a PVC
92 changes: 56 additions & 36 deletions src/schematic/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,26 @@ impl Component {
.iter()
.enumerate()
{
vols.insert(
vols.len(),
core::Volume {
config_map: Some(core::ConfigMapVolumeSource {
name: Some(container.name.clone() + i.to_string().as_str()),
..Default::default()
}),
name: container.name.clone() + i.to_string().as_str(),
vols.push(core::Volume {
config_map: Some(core::ConfigMapVolumeSource {
name: Some(container.name.clone() + i.to_string().as_str()),
..Default::default()
},
);
}),
name: container.name.clone() + i.to_string().as_str(),
..Default::default()
});
}
container.resources.volumes.iter().for_each(|v| {
// There is an ephemeral flag on v.disk. What do we do with that?
vols.push(core::Volume {
name: v.name.clone(),
empty_dir: Some(core::EmptyDirVolumeSource {
size_limit: v.disk.clone().and_then(|d| Some(Quantity(d.required))),
..Default::default()
}),
..Default::default()
});
})
}
let volumes = Some(vols);
core::PodSpec {
Expand Down Expand Up @@ -145,30 +153,7 @@ impl Component {
.collect(),
),

volume_mounts: c.config.clone().and_then(|p| {
let mut mounts = vec![];
for (i, v) in p.iter().enumerate() {
let path = Path::new(v.path.as_str())
.parent()
.unwrap()
.to_str()
.unwrap()
.to_owned();
mounts.insert(
i,
core::VolumeMount {
mount_path: path,
name: c.name.clone() + i.to_string().as_str(),
..Default::default()
},
);
}
if mounts.is_empty() {
None
} else {
Some(mounts)
}
}),
volume_mounts: c.volume_mounts(),
liveness_probe: c.liveness_probe.clone().and_then(|p| Some(p.to_probe())),
readiness_probe: c.readiness_probe.clone().and_then(|p| Some(p.to_probe())),
..Default::default()
Expand Down Expand Up @@ -264,6 +249,41 @@ pub struct Container {
pub readiness_probe: Option<HealthProbe>,
}

impl Container {
/// Generate volume mounts for a container.
pub fn volume_mounts(&self) -> Option<Vec<core::VolumeMount>> {
let mut volumes = self.config.clone().map_or(vec![], |p| {
let mut mounts = vec![];
for (i, v) in p.iter().enumerate() {
let path = Path::new(v.path.as_str())
.parent()
.unwrap()
.to_str()
.unwrap()
.to_owned();
mounts.push(core::VolumeMount {
mount_path: path,
name: self.name.clone() + i.to_string().as_str(),
..Default::default()
});
}
mounts
});
self.resources.volumes.iter().for_each(|vol| {
volumes.push(core::VolumeMount {
mount_path: vol.mount_path.clone(),
name: vol.name.clone(),
read_only: Some(vol.access_mode == AccessMode::RO),
..Default::default()
})
});
match volumes.len() {
0 => None,
_ => Some(volumes),
}
}
}

/// Workload settings describe the configuration for a workload.
///
/// This information is passed to the underlying workload defined by Component::worload_type.
Expand Down Expand Up @@ -557,8 +577,8 @@ pub struct Volume {
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Disk {
required: String,
ephemeral: bool,
pub required: String,
pub ephemeral: bool,
}
impl Default for Disk {
fn default() -> Disk {
Expand Down
38 changes: 38 additions & 0 deletions src/schematic/component_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,44 @@ fn test_to_node_seletor() {
assert_eq!(Some(selector), comp.to_node_selector())
}

#[test]
fn test_to_volume_mounts() {
let container = Container {
name: "test_container".into(),
image: "test/image".into(),
resources: Resources{
cpu: CPU {required: "1".into()},
memory: Memory {required: "128".into()},
gpu: GPU {required: "0".into()},
volumes: vec![Volume{
name: "myvol".into(),
mount_path: "/myvol".into(),
access_mode: AccessMode::RO,
disk: Some(Disk{
ephemeral: true,
required: "200M".into(),
}),
sharing_policy: SharingPolicy::Exclusive,
}],
..Default::default()
},
env: vec![],
ports: vec![],
args: None,
cmd: None,
config: Some(vec![ConfigFile{
path: "/config/file".into(),
value: Some("value".to_string()),
from_param: None,
}]),
image_pull_secret: None,
liveness_probe: None,
readiness_probe: None,
};
let mounts = container.volume_mounts();
assert_eq!(mounts.expect("at least one mount").len(), 2);
}

#[test]
fn test_to_pod_spec_with_policy() {
let component = Component::from_str(
Expand Down

0 comments on commit fac50ce

Please sign in to comment.