diff --git a/deploy.sh b/deploy.sh index b6a2c2317..525a65349 100755 --- a/deploy.sh +++ b/deploy.sh @@ -14,7 +14,8 @@ NC='\033[0m' app=$1 registry=$2 -if [ "$app" != "zookeeper" ] && [ "$app" != "rabbitmq" ] && [ "$app" != "fluent" ]; then +if [ "$app" != "zookeeper" ] && [ "$app" != "rabbitmq" ] && [ "$app" != "fluent" ]\ + && [ "$app" != "vstatefulset" ]; then echo -e "${RED}The first argument has to be one of: zookeeper, rabbitmq, fluent.${NC}" exit 1 fi diff --git a/deploy/vstatefulset/crd.yaml b/deploy/vstatefulset/crd.yaml new file mode 100644 index 000000000..b084482a0 --- /dev/null +++ b/deploy/vstatefulset/crd.yaml @@ -0,0 +1,91 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: vstatefulsets.anvil.dev +spec: + group: anvil.dev + names: + categories: [] + kind: VStatefulSet + plural: vstatefulsets + shortNames: + - vsts + singular: vstatefulset + scope: Namespaced + versions: + - additionalPrinterColumns: [] + name: v1 + schema: + openAPIV3Schema: + description: "Auto-generated derived type for VStatefulSetSpec via `CustomResource`" + properties: + spec: + properties: + minReadySeconds: + format: int32 + type: integer + podManagementPolicy: + type: string + replicas: + format: int32 + type: integer + revisionHistoryLimit: + format: int32 + type: integer + serviceName: + type: string + required: + - minReadySeconds + - podManagementPolicy + - replicas + - revisionHistoryLimit + - serviceName + type: object + status: + nullable: true + properties: + availableReplicas: + format: int32 + type: integer + collisionCount: + format: int32 + type: integer + currentReplicas: + format: int32 + type: integer + currentRevision: + type: string + observedGeneration: + format: int64 + type: integer + readyReplicas: + format: int32 + type: integer + replicas: + format: int32 + type: integer + updateRevision: + type: string + updatedReplicas: + format: int32 + type: integer + required: + - availableReplicas + - collisionCount + - currentReplicas + - currentRevision + - observedGeneration + - readyReplicas + - replicas + - updateRevision + - updatedReplicas + type: object + required: + - spec + title: VStatefulSet + type: object + served: true + storage: true + subresources: + status: {} + diff --git a/deploy/vstatefulset/deploy_local.yaml b/deploy/vstatefulset/deploy_local.yaml new file mode 100644 index 000000000..ef2a5b0e0 --- /dev/null +++ b/deploy/vstatefulset/deploy_local.yaml @@ -0,0 +1,22 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: vstatefulset-controller + namespace: vstatefulset + labels: + app.kubernetes.io/name: vstatefulset-controller +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: vstatefulset-controller + template: + metadata: + labels: + app.kubernetes.io/name: vstatefulset-controller + spec: + containers: + - image: local/vstatefulset-controller:v0.1.0 + imagePullPolicy: IfNotPresent + name: controller + serviceAccountName: vstatefulset-controller diff --git a/deploy/vstatefulset/rbac.yaml b/deploy/vstatefulset/rbac.yaml new file mode 100644 index 000000000..86dea020a --- /dev/null +++ b/deploy/vstatefulset/rbac.yaml @@ -0,0 +1,69 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + app.kubernetes.io/name: vstatefulset + name: vstatefulset +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: vstatefulset-controller + namespace: vstatefulset +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: vstatefulset-controller + name: vstatefulset-controller-role +rules: + - apiGroups: + - anvil.dev + resources: + - "*" + verbs: + - "*" + - apiGroups: + - "" + resources: + - pods + - services + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + - serviceaccounts + verbs: + - "*" + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - "*" + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - "*" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: vstatefulset-controller + name: vstatefulset-controller-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: vstatefulset-controller-role +subjects: + - kind: ServiceAccount + name: vstatefulset-controller + namespace: vstatefulset diff --git a/deploy/vstatefulset/vstatefulset.yaml b/deploy/vstatefulset/vstatefulset.yaml new file mode 100644 index 000000000..3040d29ad --- /dev/null +++ b/deploy/vstatefulset/vstatefulset.yaml @@ -0,0 +1,12 @@ +apiVersion: anvil.dev/v1 +kind: VStatefulSet +metadata: + name: vstatefulset + namespace: default +spec: + serviceName: foo + replicas: 4 + podManagementPolicy: dummy + revisionHistoryLimit: 4 + minReadySeconds: 42 + \ No newline at end of file diff --git a/src/deps_hack/src/lib.rs b/src/deps_hack/src/lib.rs index 6c29b0d08..4719d93cc 100644 --- a/src/deps_hack/src/lib.rs +++ b/src/deps_hack/src/lib.rs @@ -278,3 +278,52 @@ pub struct VReplicaSetSpec { pub selector: k8s_openapi::apimachinery::pkg::apis::meta::v1::LabelSelector, pub template: Option, } + +#[derive( + kube::CustomResource, Debug, Clone, serde::Deserialize, serde::Serialize, schemars::JsonSchema, +)] +#[kube(group = "anvil.dev", version = "v1", kind = "VStatefulSet")] +#[kube(shortname = "vsts", namespaced)] +#[kube(status = "VStatefulSetStatus")] +pub struct VStatefulSetSpec { + #[serde(rename = "serviceName")] + pub service_name: String, + // pub selector: k8s_openapi::apimachinery::pkg::apis::meta::v1::LabelSelector, + // pub template: k8s_openapi::api::core::v1::PodTemplateSpec, + pub replicas: i32, + // #[serde(rename = "updateStrategy")] + // pub update_strategy: Option, + #[serde(rename = "podManagementPolicy")] + pub pod_management_policy: String, + #[serde(rename = "revisionHistoryLimit")] + pub revision_history_limit: i32, + // #[serde(rename = "volumeClaimTemplates")] + // pub volume_claim_templates: Option>, + #[serde(rename = "minReadySeconds")] + pub min_ready_seconds: i32, + // #[serde(rename = "persistentVolumeClaimRetentionPolicy")] + // pub persistent_volume_claim_retention_policy: Option, + // pub ordinals: Option, +} + +#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] +pub struct VStatefulSetStatus { + pub replicas: i32, + #[serde(rename = "readyReplicas")] + pub ready_replicas: i32, + #[serde(rename = "currentReplicas")] + pub current_replicas: i32, + #[serde(rename = "updatedReplicas")] + pub updated_replicas: i32, + #[serde(rename = "availableReplicas")] + pub available_replicas: i32, + #[serde(rename = "collisionCount")] + pub collision_count: i32, + // pub conditions: Option>, + #[serde(rename = "currentRevision")] + pub current_revision: String, + #[serde(rename = "updateRevision")] + pub update_revision: String, + #[serde(rename = "observedGeneration")] + pub observed_generation: i64, +} diff --git a/src/vstatefulset_controller.rs b/src/vstatefulset_controller.rs new file mode 100644 index 000000000..60d7fe1a8 --- /dev/null +++ b/src/vstatefulset_controller.rs @@ -0,0 +1,48 @@ +// Copyright 2024 VMware, Inc. +// SPDX-License-Identifier: MIT +#![allow(unused_imports)] + +pub mod external_api; +pub mod kubernetes_api_objects; +pub mod kubernetes_cluster; +pub mod reconciler; +pub mod shim_layer; +pub mod state_machine; +pub mod temporal_logic; +pub mod vstd_ext; + +use builtin::*; +use builtin_macros::*; + +use crate::external_api::exec::*; +use deps_hack::anyhow::Result; +use deps_hack::futures; +use deps_hack::kube::CustomResourceExt; +use deps_hack::serde_yaml; +use deps_hack::tokio; +use shim_layer::controller_runtime::run_controller; +use std::env; + +verus! { + +#[verifier(external)] +#[tokio::main] +async fn main() -> Result<()> { + let args: Vec = env::args().collect(); + let cmd = args[1].clone(); + + if cmd == String::from("export") { + println!("exporting custom resource definition"); + println!("{}", serde_yaml::to_string(&deps_hack::VStatefulSet::crd())?); + } else if cmd == String::from("run") { + println!("running vstatefulset-controller"); + println!("controller terminated"); + } else if cmd == String::from("crash") { + println!("running vstatefulset-controller in crash-testing mode"); + println!("controller terminated"); + } else { + println!("wrong command; please use \"export\", \"run\" or \"crash\""); + } + Ok(()) +} +}