Skip to content

Commit

Permalink
chore(opertor): example with nginx
Browse files Browse the repository at this point in the history
  • Loading branch information
stephane-segning committed Jul 28, 2024
1 parent 001b7c0 commit 197c3d6
Show file tree
Hide file tree
Showing 20 changed files with 370 additions and 49 deletions.
79 changes: 79 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Build Translator

on:
push:
branches:
- '**'
tags-ignore:
- 'v*'
paths:
- 'wazuh-operator/**'

env:
CARGO_TERM_COLOR: always
REGISTRY: ghcr.io
IMAGE_NAME: wazuh-operator

jobs:
build:

runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v4

- name: Build Translator
working-directory: wazuh-operator
run: cargo build --verbose && cargo test --verbose

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to the Docker registry
id: login
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- id: lowercase
name: Lowercase image name
uses: AsZc/change-string-case-action@v6
with:
string: ${{ env.IMAGE_NAME }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ steps.lowercase.outputs.lowercase }}
tags: |
type=raw,value=latest
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Build and push Docker image
uses: docker/build-push-action@v5
if: github.event_name != 'pull_request'
with:
context: ./wazuh-operator
push: "${{ github.ref == 'refs/heads/main' && 'true' || 'false' }}"
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
2 changes: 1 addition & 1 deletion example/simple.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ metadata:
name: wazuh-cluster-sample
namespace: my-namespace
spec:
replicas: 3
replicas: 3
21 changes: 11 additions & 10 deletions wazuh-operator/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions wazuh-operator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ version = "0.1.0"
edition = "2021"

[dependencies]
kube = { version = "0.92.1", features = ["runtime", "derive", "admission", "rustls-tls", "ws", "socks5", "runtime"] }
kube = { version = "0.93.1", features = ["runtime", "derive", "admission", "rustls-tls", "ws", "socks5", "runtime"] }
schemars = "0.8.21"
k8s-openapi = { version = "0.22.0", features = ["latest"] }
k8s-openapi = { version = "0.22.0", features = ["latest", "schemars"] }
tokio = { version = "1.38.1", features = ["full"] }
serde = { version = "1.0.203", features = ["derive"] }
serde_json = { version = "1.0.120" }
Expand Down
19 changes: 19 additions & 0 deletions wazuh-operator/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM rust as base

WORKDIR /app

FROM base as builder

# Copy the Cargo.toml and Cargo.lock files to cache dependencies
COPY ./ ./

# Build the dependencies
RUN cargo build --release

FROM base

WORKDIR /app

COPY --from=builder /app/target/release/wazuh-operator /app/wazuh-operator

CMD ["/app/wazuh-operator"]
12 changes: 12 additions & 0 deletions wazuh-operator/src/controller/error_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use std::sync::Arc;
use std::time::Duration;

use kube::runtime::controller::Action;
use crate::errors::*;
use crate::crds::wazuh_cluster::WazuhCluster;
use crate::models::data::Data;

pub fn error_policy(wazuh: Arc<WazuhCluster>, error: &Error, _ctx: Arc<Data>) -> Action {
eprintln!("Reconciliation error:\n{:?}.\n{:?}", error, wazuh);
Action::requeue(Duration::from_secs(60))
}
42 changes: 42 additions & 0 deletions wazuh-operator/src/controller/finalizer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use kube::{Api, Client};
use anyhow::*;
use kube::api::{Patch, PatchParams};
use serde_json::Value;
use crate::crds::wazuh_cluster::WazuhCluster;

pub async fn add_finalizer(client: Client, name: &str, namespace: &str) -> Result<()> {
let api: Api<WazuhCluster> = Api::namespaced(client, namespace);
let finalizer = json!({
"metadata": {
"finalizers": ["wazuh.adorsys.team/finalizer"]
}
});

let patch: Patch<&Value> = Patch::Merge(&finalizer);
api.patch(name, &PatchParams::default(), &patch).await?;

Ok(())
}

/// Removes all finalizers from an `Echo` resource. If there are no finalizers already, this
/// action has no effect.
///
/// # Arguments:
/// - `client` - Kubernetes client to modify the `Echo` resource with.
/// - `name` - Name of the `Echo` resource to modify. Existence is not verified
/// - `namespace` - Namespace where the `Echo` resource with given `name` resides.
///
/// Note: Does not check for resource's existence for simplicity.
pub async fn delete_finalizer(client: Client, name: &str, namespace: &str) -> Result<()> {
let api: Api<WazuhCluster> = Api::namespaced(client, namespace);
let finalizer: Value = json!({
"metadata": {
"finalizers": null
}
});

let patch: Patch<&Value> = Patch::Merge(&finalizer);
api.patch(name, &PatchParams::default(), &patch).await?;

Ok(())
}
30 changes: 5 additions & 25 deletions wazuh-operator/src/controller/handler.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,26 @@
use std::sync::Arc;
use std::time::Duration;

use futures::StreamExt;
use kube::{Api, Client};
use kube::runtime::Controller;
use kube::runtime::controller::Action;
use kube::runtime::reflector::ObjectRef;
use kube::runtime::watcher::Config;

use crate::controller::error_handler::error_policy;
use crate::controller::reconcile_wazuh::reconcile_wazuh;
use crate::crds::wazuh_cluster::WazuhCluster;
use crate::models::cluster_ref::WazuhClusterRef;
use crate::models::data::Data;

type WazuhClusterRef = ObjectRef<WazuhCluster>;

pub async fn watch_wazuh_cluster(client: Client) {
// Create an API for the WazuhCluster CRD
let crd_api: Api<WazuhCluster> = Api::all(client.clone());

// Define the reconciliation function
async fn reconcile(_wazuh: Arc<WazuhCluster>, _ctx: Arc<Data>) -> Result<Action, kube::Error> {
info!("Reconciling WazuhCluster");

let patch = json!({"spec": {
"activeDeadlineSeconds": 5
}});

// Implement your reconciliation logic here
Ok(Action::requeue(Duration::from_secs(300)))
}

// Define the error policy
fn error_policy(_wazuh: Arc<WazuhCluster>, _error: &kube::Error, _ctx: Arc<Data>) -> Action {
error!("Reconciliation failed");
Action::requeue(Duration::from_secs(60))
}

// Create a controller for the WazuhCluster CRD
Controller::new(crd_api, Config::default())
.run(reconcile, error_policy, Arc::from(Data::new(client.clone())))
.run(reconcile_wazuh, error_policy, Arc::from(Data::new(client.clone())))
.for_each(|res| async move {
match res {
Ok((WazuhClusterRef { name, .. }, _)) => info!("Reconciled {:?}", name),
Ok((WazuhClusterRef { name, namespace, .. }, _)) => debug!("Reconciled {:?} in {:?}", name, namespace.unwrap_or_else(|| "default".to_string())),
Err(e) => error!("Reconcile failed: {:?}", e),
}
})
Expand Down
5 changes: 4 additions & 1 deletion wazuh-operator/src/controller/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
pub mod handler;
pub mod handler;
pub mod error_handler;
mod reconcile_wazuh;
mod finalizer;
47 changes: 47 additions & 0 deletions wazuh-operator/src/controller/reconcile_wazuh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::sync::Arc;
use std::time::Duration;

use kube::runtime::controller::Action;
use kube::runtime::reflector::Lookup;

use crate::controller::finalizer::{add_finalizer, delete_finalizer};
use crate::crds::wazuh_cluster::WazuhCluster;
use crate::models::crd_action::WazuhClusterAction;
use crate::models::data::Data;
use crate::services::determine_action::determine_action;
use crate::services::nginx_deployment::{update_deployment, delete_deployment, update_status};
use crate::errors::*;

pub async fn reconcile_wazuh(wazuh: Arc<WazuhCluster>, ctx: Arc<Data>) -> Result<Action, Error> {
info!("Reconciling WazuhCluster");

let namespace = &wazuh.namespace().unwrap();
let name = &wazuh.name().unwrap();

match determine_action(&wazuh) {
WazuhClusterAction::Create => {
debug!("Creating WazuhCluster {:?}", name);
// Add the finalizer and create the deployment
add_finalizer(ctx.client.clone(), name, namespace).await?;
update_deployment(ctx.client.clone(), &wazuh, name, namespace).await?;
update_status(ctx.client.clone(), &wazuh, name, namespace).await?;
debug!("Created WazuhCluster {:?}", name);
Ok(Action::requeue(Duration::from_secs(20)))
}
WazuhClusterAction::Delete => {
debug!("Deleting WazuhCluster {:?}", name);
// Delete the deployment and remove the finalizer
delete_deployment(ctx.client.clone(), &wazuh, name, namespace).await?;
delete_finalizer(ctx.client.clone(), name, namespace).await?;
debug!("Deleted WazuhCluster {:?}", name);
Ok(Action::await_change())
}
WazuhClusterAction::Update => {
debug!("Updating WazuhCluster {:?}", name);
update_deployment(ctx.client.clone(), &wazuh, name, namespace).await?;
update_status(ctx.client.clone(), &wazuh, name, namespace).await?;
debug!("Updated WazuhCluster {:?}", name);
Ok(Action::requeue(Duration::from_secs(10)))
}
}
}
3 changes: 2 additions & 1 deletion wazuh-operator/src/crds/wazuh_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ use schemars::JsonSchema;

#[derive(CustomResource, Debug, Clone, Deserialize, Serialize, JsonSchema)]
#[kube(shortname = "wzcl", group = "wazuh.adorsys.team", version = "v1", kind = "WazuhCluster", namespaced)]
#[kube(status = "WazuhClusterStatus")]
pub struct WazuhClusterSpec {
pub replicas: i32,
}

#[derive(Deserialize, Serialize, Clone, Debug)]
#[derive(Deserialize, Serialize, Clone, Debug, Default, JsonSchema)]
pub struct WazuhClusterStatus {
pub available_replicas: i32,
}
18 changes: 11 additions & 7 deletions wazuh-operator/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use thiserror::Error;

#[derive(Debug, Error)]
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Failed to create WazuhCluster: {0}")]
WazuhClusterCreationFailed(#[source] kube::Error),
#[error("App reported error: {source}")]
AnyError {
#[from]
source: anyhow::Error,
},

#[error("MissingObjectKey: {0}")]
MissingObjectKey(&'static str),
#[error("Kubernetes reported error: {source}")]
KubeError {
#[from]
source: kube::Error,
},
}
Loading

0 comments on commit 197c3d6

Please sign in to comment.