feat: add actual alloy component

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2024-12-02 23:11:38 +01:00
parent be4d755d51
commit fcce281da3
8 changed files with 676 additions and 12 deletions

View File

@@ -1,4 +1,136 @@
#[allow(dead_code)]
pub mod component {
#[allow(dead_code)]
pub mod churn_tasks {
#[allow(dead_code, clippy::all)]
pub mod process {
#[used]
#[doc(hidden)]
static __FORCE_SECTION_REF: fn() = super::super::super::__link_custom_section_describing_imports;
use super::super::super::_rt;
#[derive(Debug)]
#[repr(transparent)]
pub struct Process {
handle: _rt::Resource<Process>,
}
impl Process {
#[doc(hidden)]
pub unsafe fn from_handle(handle: u32) -> Self {
Self {
handle: _rt::Resource::from_handle(handle),
}
}
#[doc(hidden)]
pub fn take_handle(&self) -> u32 {
_rt::Resource::take_handle(&self.handle)
}
#[doc(hidden)]
pub fn handle(&self) -> u32 {
_rt::Resource::handle(&self.handle)
}
}
unsafe impl _rt::WasmResource for Process {
#[inline]
unsafe fn drop(_handle: u32) {
#[cfg(not(target_arch = "wasm32"))]
unreachable!();
#[cfg(target_arch = "wasm32")]
{
#[link(
wasm_import_module = "component:churn-tasks/process@0.1.0"
)]
extern "C" {
#[link_name = "[resource-drop]process"]
fn drop(_: u32);
}
drop(_handle);
}
}
}
impl Process {
#[allow(unused_unsafe, clippy::all)]
pub fn new() -> Self {
unsafe {
#[cfg(target_arch = "wasm32")]
#[link(
wasm_import_module = "component:churn-tasks/process@0.1.0"
)]
extern "C" {
#[link_name = "[constructor]process"]
fn wit_import() -> i32;
}
#[cfg(not(target_arch = "wasm32"))]
fn wit_import() -> i32 {
unreachable!()
}
let ret = wit_import();
Process::from_handle(ret as u32)
}
}
}
impl Process {
#[allow(unused_unsafe, clippy::all)]
pub fn run_process(&self, inputs: &[_rt::String]) -> _rt::String {
unsafe {
#[repr(align(4))]
struct RetArea([::core::mem::MaybeUninit<u8>; 8]);
let mut ret_area = RetArea(
[::core::mem::MaybeUninit::uninit(); 8],
);
let vec1 = inputs;
let len1 = vec1.len();
let layout1 = _rt::alloc::Layout::from_size_align_unchecked(
vec1.len() * 8,
4,
);
let result1 = if layout1.size() != 0 {
let ptr = _rt::alloc::alloc(layout1).cast::<u8>();
if ptr.is_null() {
_rt::alloc::handle_alloc_error(layout1);
}
ptr
} else {
::core::ptr::null_mut()
};
for (i, e) in vec1.into_iter().enumerate() {
let base = result1.add(i * 8);
{
let vec0 = e;
let ptr0 = vec0.as_ptr().cast::<u8>();
let len0 = vec0.len();
*base.add(4).cast::<usize>() = len0;
*base.add(0).cast::<*mut u8>() = ptr0.cast_mut();
}
}
let ptr2 = ret_area.0.as_mut_ptr().cast::<u8>();
#[cfg(target_arch = "wasm32")]
#[link(
wasm_import_module = "component:churn-tasks/process@0.1.0"
)]
extern "C" {
#[link_name = "[method]process.run-process"]
fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8);
}
#[cfg(not(target_arch = "wasm32"))]
fn wit_import(_: i32, _: *mut u8, _: usize, _: *mut u8) {
unreachable!()
}
wit_import((self).handle() as i32, result1, len1, ptr2);
let l3 = *ptr2.add(0).cast::<*mut u8>();
let l4 = *ptr2.add(4).cast::<usize>();
let len5 = l4;
let bytes5 = _rt::Vec::from_raw_parts(l3.cast(), len5, len5);
if layout1.size() != 0 {
_rt::alloc::dealloc(result1.cast(), layout1);
}
_rt::string_lift(bytes5)
}
}
}
}
}
}
#[allow(dead_code)]
pub mod exports {
#[allow(dead_code)]
pub mod component {
@@ -82,6 +214,90 @@ pub mod exports {
}
}
mod _rt {
use core::fmt;
use core::marker;
use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
/// A type which represents a component model resource, either imported or
/// exported into this component.
///
/// This is a low-level wrapper which handles the lifetime of the resource
/// (namely this has a destructor). The `T` provided defines the component model
/// intrinsics that this wrapper uses.
///
/// One of the chief purposes of this type is to provide `Deref` implementations
/// to access the underlying data when it is owned.
///
/// This type is primarily used in generated code for exported and imported
/// resources.
#[repr(transparent)]
pub struct Resource<T: WasmResource> {
handle: AtomicU32,
_marker: marker::PhantomData<T>,
}
/// A trait which all wasm resources implement, namely providing the ability to
/// drop a resource.
///
/// This generally is implemented by generated code, not user-facing code.
#[allow(clippy::missing_safety_doc)]
pub unsafe trait WasmResource {
/// Invokes the `[resource-drop]...` intrinsic.
unsafe fn drop(handle: u32);
}
impl<T: WasmResource> Resource<T> {
#[doc(hidden)]
pub unsafe fn from_handle(handle: u32) -> Self {
debug_assert!(handle != u32::MAX);
Self {
handle: AtomicU32::new(handle),
_marker: marker::PhantomData,
}
}
/// Takes ownership of the handle owned by `resource`.
///
/// Note that this ideally would be `into_handle` taking `Resource<T>` by
/// ownership. The code generator does not enable that in all situations,
/// unfortunately, so this is provided instead.
///
/// Also note that `take_handle` is in theory only ever called on values
/// owned by a generated function. For example a generated function might
/// take `Resource<T>` as an argument but then call `take_handle` on a
/// reference to that argument. In that sense the dynamic nature of
/// `take_handle` should only be exposed internally to generated code, not
/// to user code.
#[doc(hidden)]
pub fn take_handle(resource: &Resource<T>) -> u32 {
resource.handle.swap(u32::MAX, Relaxed)
}
#[doc(hidden)]
pub fn handle(resource: &Resource<T>) -> u32 {
resource.handle.load(Relaxed)
}
}
impl<T: WasmResource> fmt::Debug for Resource<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Resource").field("handle", &self.handle).finish()
}
}
impl<T: WasmResource> Drop for Resource<T> {
fn drop(&mut self) {
unsafe {
match self.handle.load(Relaxed) {
u32::MAX => {}
other => T::drop(other),
}
}
}
}
pub use alloc_crate::string::String;
pub use alloc_crate::alloc;
pub use alloc_crate::vec::Vec;
pub unsafe fn string_lift(bytes: Vec<u8>) -> String {
if cfg!(debug_assertions) {
String::from_utf8(bytes).unwrap()
} else {
String::from_utf8_unchecked(bytes)
}
}
#[cfg(target_arch = "wasm32")]
pub fn run_ctors_once() {
wit_bindgen_rt::run_ctors_once();
@@ -93,8 +309,6 @@ mod _rt {
let layout = alloc::Layout::from_size_align_unchecked(size, align);
alloc::dealloc(ptr, layout);
}
pub use alloc_crate::string::String;
pub use alloc_crate::alloc;
extern crate alloc as alloc_crate;
}
/// Generates `#[no_mangle]` functions to export the specified type as the
@@ -130,13 +344,16 @@ pub(crate) use __export_alloy_impl as export;
#[cfg(target_arch = "wasm32")]
#[link_section = "component-type:wit-bindgen:0.35.0:component:alloy:alloy:encoded world"]
#[doc(hidden)]
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 244] = *b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07y\x01A\x02\x01A\x02\x01\
B\x06\x01@\0\0s\x04\0\x02id\x01\0\x01@\0\0\x7f\x04\0\x0ashould-run\x01\x01\x01@\0\
\x01\0\x04\0\x07execute\x01\x02\x04\0\x20component:churn-tasks/task@0.1.0\x05\0\x04\
\0\x15component:alloy/alloy\x04\0\x0b\x0b\x01\0\x05alloy\x03\0\0\0G\x09producers\
\x01\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rust\x060.35\
.0";
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 390] = *b"\
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\x8a\x02\x01A\x02\x01\
A\x04\x01B\x08\x04\0\x07process\x03\x01\x01i\0\x01@\0\0\x01\x04\0\x14[constructo\
r]process\x01\x02\x01h\0\x01ps\x01@\x02\x04self\x03\x06inputs\x04\0s\x04\0\x1b[m\
ethod]process.run-process\x01\x05\x03\0#component:churn-tasks/process@0.1.0\x05\0\
\x01B\x06\x01@\0\0s\x04\0\x02id\x01\0\x01@\0\0\x7f\x04\0\x0ashould-run\x01\x01\x01\
@\0\x01\0\x04\0\x07execute\x01\x02\x04\0\x20component:churn-tasks/task@0.1.0\x05\
\x01\x04\0\x15component:alloy/alloy\x04\0\x0b\x0b\x01\0\x05alloy\x03\0\0\0G\x09p\
roducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rust\
\x060.35.0";
#[inline(never)]
#[doc(hidden)]
pub fn __link_custom_section_describing_imports() {

View File

@@ -1,8 +1,15 @@
use bindings::exports::component::churn_tasks::task::Guest;
use std::{io::Write, path::PathBuf};
use bindings::{
component::churn_tasks::process::Process, exports::component::churn_tasks::task::Guest,
};
#[allow(warnings)]
mod bindings;
const ALLOY_CONFIG_PATH: &str = "/etc/alloy/config.alloy";
const ALLOY_CONFIG_FILE: &str = include_str!("../files/config.alloy");
struct Component;
impl Guest for Component {
@@ -11,12 +18,143 @@ impl Guest for Component {
}
fn should_run() -> bool {
true
let output = Process::new().run_process(
&["systemctl", "is-enabled", "alloy.service"]
.into_iter()
.map(|i| i.into())
.collect::<Vec<String>>(),
);
if !output.contains("enabled") {
return true;
}
let output = Process::new().run_process(
&["systemctl", "is-active", "alloy.service"]
.into_iter()
.map(|i| i.into())
.collect::<Vec<String>>(),
);
if output.contains("inactive") {
return true;
}
match std::fs::read_to_string(ALLOY_CONFIG_PATH) {
Ok(content) => return content != ALLOY_CONFIG_FILE,
Err(e) => {
if e.kind() == std::io::ErrorKind::NotFound {
return true;
}
}
}
false
}
fn execute() {
println!("I was run");
println!("running alloy installation");
let output = Process::new().run_process(
&["systemctl", "is-enabled", "alloy.service"]
.into_iter()
.map(|i| i.into())
.collect::<Vec<String>>(),
);
if !output.contains("enabled") {
install_alloy().expect("to be able to install alloy");
}
let restart = match std::fs::read_to_string(ALLOY_CONFIG_PATH) {
Ok(content) => {
if content != ALLOY_CONFIG_FILE {
let mut file = std::fs::File::create(ALLOY_CONFIG_PATH)
.expect("to be able to create file");
file.write_all(ALLOY_CONFIG_FILE.as_bytes())
.expect("to be able to write file");
file.flush().expect("to be able to flush file");
true
} else {
false
}
}
Err(e) => {
if e.kind() == std::io::ErrorKind::NotFound {
if let Some(parent) = PathBuf::from(ALLOY_CONFIG_PATH).parent() {
std::fs::create_dir_all(parent)
.expect("to be able to create dir for alloy");
}
let mut file = std::fs::File::create(ALLOY_CONFIG_PATH)
.expect("to be able to create file");
file.write_all(ALLOY_CONFIG_FILE.as_bytes())
.expect("to be able to write file");
file.flush().expect("to be able to flush file");
false
} else {
false
}
}
};
if restart {
restart_alloy().expect("to be able to restart alloy");
return;
}
let output = Process::new().run_process(
&["systemctl", "is-active", "alloy.service"]
.into_iter()
.map(|i| i.into())
.collect::<Vec<String>>(),
);
if output.contains("inactive") {
run_and_activate_alloy().expect("to be able to active alloy");
}
}
}
fn install_alloy() -> Result<(), String> {
println!("=== installing alloy ===");
run_command(["apt", "install", "gpg"])?;
run_command(["mkdir", "-p", "/etc/apt/keyrings/"])?;
run_command(["bash", "-c", "wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null && echo \"deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main\" | sudo tee /etc/apt/sources.list.d/grafana.list"])?;
run_command(["apt-get", "update"])?;
run_command(["apt-get", "install", "alloy"])?;
println!("=== finished installing alloy ===");
Ok(())
}
fn restart_alloy() -> Result<(), String> {
println!("=== restarting alloy ===");
run_command(["systemctl", "restart", "alloy"])?;
println!("=== finished restarting alloy ===");
Ok(())
}
fn run_and_activate_alloy() -> Result<(), String> {
println!("=== starting alloy ===");
run_command(["systemctl", "start", "alloy"])?;
println!("=== finished starting alloy ===");
println!("=== enabling alloy ===");
run_command(["systemctl", "enable", "alloy"])?;
println!("=== finished enabling alloy ===");
Ok(())
}
fn run_command(input: impl IntoIterator<Item = impl Into<String>>) -> Result<(), String> {
let args = input.into_iter().map(|i| i.into()).collect::<Vec<String>>();
println!("running {}", args.join(" "));
let output = Process::new().run_process(&args);
println!("output: {}", output);
Ok(())
}
bindings::export!(Component with_types_in bindings);