1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
use serde::Deserialize;
use serde::Serialize;

use k8_obj_core::pod::PodSpec;
use crate::core::metadata::{Crd, CrdNames, DefaultHeader, LabelSelector, Spec, Status, TemplateSpec};

const STATEFUL_API: Crd = Crd {
    group: "apps",
    version: "v1",
    names: CrdNames {
        kind: "StatefulSet",
        plural: "statefulsets",
        singular: "statefulset",
    },
};

#[derive(Deserialize, Serialize, Debug, Default, Clone)]
#[serde(rename_all = "camelCase", default)]
pub struct StatefulSetSpec {
    pub pod_management_policy: Option<PodMangementPolicy>,
    pub replicas: Option<u16>,
    pub revision_history_limit: Option<u16>,
    pub selector: LabelSelector,
    pub service_name: String,
    pub template: TemplateSpec<PodSpec>,
    pub volume_claim_templates: Vec<TemplateSpec<PersistentVolumeClaim>>,
    pub update_strategy: Option<StatefulSetUpdateStrategy>,
}

impl Spec for StatefulSetSpec {
    type Status = StatefulSetStatus;
    type Header = DefaultHeader;

    fn metadata() -> &'static Crd {
        &STATEFUL_API
    }
}

#[derive(Deserialize, Serialize, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub struct StatefulSetUpdateStrategy {
    pub _type: String,
    pub rolling_ipdate: Option<RollingUpdateStatefulSetStrategy>,
}

#[derive(Deserialize, Serialize, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RollingUpdateStatefulSetStrategy {
    partition: u32,
}

#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
pub enum PodMangementPolicy {
    OrderedReady,
    Parallel,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PersistentVolumeClaim {
    pub access_modes: Vec<VolumeAccessMode>,
    pub storage_class_name: String,
    pub resources: ResourceRequirements,
}

#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
pub enum VolumeAccessMode {
    ReadWriteOnce,
    ReadWrite,
    ReadOnlyMany,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ResourceRequirements {
    pub requests: VolumeRequest,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct VolumeRequest {
    pub storage: String,
}

#[derive(Deserialize, Serialize, Default, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct StatefulSetStatus {
    pub replicas: u16,
    pub collision_count: Option<u32>,
    #[serde(default)]
    pub conditions: Vec<StatefulSetCondition>,
    pub current_replicas: Option<u16>,
    pub current_revision: Option<String>,
    pub observed_generation: Option<u32>,
    pub ready_replicas: Option<u16>,
    pub update_revision: Option<String>,
    pub updated_replicas: Option<u16>,
}

impl Status for StatefulSetStatus {}

#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
pub enum StatusEnum {
    True,
    False,
    Unknown,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct StatefulSetCondition {
    pub message: String,
    pub reason: StatusEnum,
    pub status: String,
    #[serde(rename = "type")]
    pub _type: String,
}

/*
#[cfg(test)]
mod test {

    use serde_json;
    use serde_json::json;

    use super::LabelSelector;
    use super::StatefulSetSpec;
    use k8_diff::Changes;
    use k8_metadata::cluster::ClusterSpec;
    use k8_metadata::cluster::Configuration;
    use k8_metadata::cluster::Cluster;
    use k8_metadata::cluster::ClusterEndpoint;

    #[test]
    fn test_label_selector() {
        let selector = LabelSelector::new_labels(vec![("app".to_owned(), "test".to_owned())]);

        let maps = selector.match_labels;
        assert_eq!(maps.len(), 1);
        assert_eq!(maps.get("app").unwrap(), "test");
    }

    #[test]
    fn test_cluster_to_stateful() {
        let cluster = ClusterSpec {
            cluster: Cluster {
                replicas: Some(3),
                rack: Some("rack1".to_string()),
                public_endpoint: Some(ClusterEndpoint::new(9005)),
                private_endpoint: Some(ClusterEndpoint::new(9006)),
                controller_endpoint: Some(ClusterEndpoint::new(9004)),
            },
            configuration: Some(Configuration::default()),
            env: None,
        };

        let stateful: StatefulSetSpec = (&cluster).into();
        assert_eq!(stateful.replicas, Some(3));
        let mut stateful2 = stateful.clone();
        stateful2.replicas = Some(2);

        let state1_json = serde_json::to_value(stateful).expect("json");
        let state2_json = serde_json::to_value(stateful2).expect("json");
        let diff = state1_json.diff(&state2_json).expect("diff");
        let json_diff = serde_json::to_value(diff).unwrap();
        assert_eq!(
            json_diff,
            json!({
                "replicas": 2
            })
        );
    }


    /*
    * TODO: make this as utility
    use std::io::Read;
    use std::fs::File;
    use k8_metadata_core::metadata::ObjectMeta;
    use k8_metadata_core::metadata::K8Obj;
    use super::StatefulSetStatus;
    use super::TemplateSpec;
    use super::PodSpec;
    use super::ContainerSpec;
    use super::ContainerPortSpec;

    #[test]
    fn test_decode_statefulset()  {
        let file_name = "/private/tmp/f1.json";

        let mut f = File::open(file_name).expect("open failed");
        let mut contents = String::new();
        f.read_to_string(&mut contents).expect("read file");
       // let st: StatefulSetSpec = serde_json::from_slice(&buffer).expect("error");
        let st: K8Obj<StatefulSetSpec,StatefulSetStatus> = serde_json::from_str(&contents).expect("error");
        println!("st: {:#?}",st);
        assert!(true);
    }
    */

}
*/