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
//
// Copyright (c) 2021 RepliXio Ltd. All rights reserved.
// Use is subject to license terms.
//

use std::fmt;

use k8s_openapi::{api::core::v1::Namespace, apimachinery::pkg::apis::meta::v1::OwnerReference};
// use k8s_openapi::api::core::v1::{ConfigMap, Namespace, Node, Pod, Secret};
// use serde_json as json;
use kube::client;
use kube::{Resource, ResourceExt};

use super::StatehubCluster;

mod helper;

pub struct Kubectl {
    client: kube::Client,
    controller: bool,
}

impl Kubectl {
    #[must_use]
    pub fn new(client: client::Client) -> Self {
        let controller = false;
        Self { client, controller }
    }

    #[must_use]
    pub fn controller(self, yes: bool) -> Self {
        Self {
            controller: yes,
            ..self
        }
    }

    #[must_use]
    pub fn clusters_api(&self) -> kube::Api<StatehubCluster> {
        self.api::<StatehubCluster>()
    }

    pub async fn get_clusters(&self) -> kube::Result<Vec<StatehubCluster>> {
        let lp = self.list_params();
        self.clusters_api().list(&lp).await.map(|list| list.items)
    }

    pub async fn create_namespace(&self, statehub: &StatehubCluster) -> kube::Result<Namespace> {
        // let namespace = json::from_value(json::json!({
        //     "apiVerion": "v1",
        //     "kind": "Namespace",
        //     "metadata": {
        //         "name": namespace,
        //     }
        // }))?;
        let name = statehub.name();
        let uid = statehub.uid().unwrap();
        let api_version = StatehubCluster::api_version(&()).to_string();
        let kind = StatehubCluster::kind(&()).to_string();
        let controller = if self.controller { Some(true) } else { None };
        let _owner = OwnerReference {
            api_version,
            controller,
            kind,
            name,
            uid,
            ..OwnerReference::default()
        };
        let mut namespace = Namespace::default();
        namespace.metadata.name = Some(statehub.spec.namespace.clone());
        // namespace.metadata.owner_references.push(owner);
        let pp = self.post_params();
        self.api::<Namespace>().create(&pp, &namespace).await
    }

    pub async fn delete_namespace(&self, statehub: &StatehubCluster) -> kube::Result<()> {
        let dp = self.delete_params();
        let namespace = &statehub.spec.namespace;
        self.api::<Namespace>()
            .delete(namespace, &dp)
            .await?
            .map_left(|object| log::trace!("Deleting namespace: {:?}", object.status))
            .map_right(|status| log::trace!("Deleted namespace: {:?}", status));
        Ok(())
    }

    pub async fn check_namespace(&self, statehub: &StatehubCluster) -> kube::Result<Namespace> {
        self.api::<Namespace>().get(&statehub.spec.namespace).await
    }

    pub async fn ensure_namespace_exists(
        &self,
        statehub: &StatehubCluster,
    ) -> kube::Result<Namespace> {
        if let Ok(namespace) = self.check_namespace(statehub).await {
            Ok(namespace)
        } else {
            self.create_namespace(statehub).await
        }
    }
}

impl fmt::Debug for Kubectl {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Kubectl")
            .field("client", &"kube::Client")
            .finish()
    }
}