Skip to content

Commit

Permalink
Merge pull request #9 from isambard-sc/feature_waldur
Browse files Browse the repository at this point in the history
Feature waldur

[ci skip]
  • Loading branch information
chryswoods authored Dec 17, 2024
2 parents a1d1a6e + 573c652 commit 8de1c11
Show file tree
Hide file tree
Showing 18 changed files with 1,414 additions and 337 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Added automatic building of Python Linux aarch64 binaries, so that
the Python module can be used on ARM64 systems.

- Cleaned up the Python API and added in lots of convenience functions.
Objects are now correctly returned from the `run` function, so that you
don't need to parse anything. Also added in the ability to default
wait for a command to run

- Added in extra commands to add and remove projects, list users in a
project, and list projects in a portal. Some of these are still stubbed.

- Added in `ProjectIdentifier` and `ProjectMapping` to mirror the
equivalent `User` classes. Also cleaned up the concept of local
users and groups, so that a `UserMapping` maps a user to a local
unix username and unix group, while the `ProjectMapping` maps a
project to a local unix group.

## [0.1.1] - 2024-12-02
### Added
Expand Down
166 changes: 159 additions & 7 deletions cluster/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ use templemeads::agent;
use templemeads::agent::instance::{process_args, run, Defaults};
use templemeads::agent::Type as AgentType;
use templemeads::async_runnable;
use templemeads::grammar::Instruction::{AddUser, RemoveUser};
use templemeads::grammar::{UserIdentifier, UserMapping};
use templemeads::grammar::Instruction::{
AddProject, AddUser, GetProjects, GetUsers, RemoveProject, RemoveUser,
};
use templemeads::grammar::{ProjectIdentifier, ProjectMapping, UserIdentifier, UserMapping};
use templemeads::job::{Envelope, Job};
use templemeads::Error;

Expand Down Expand Up @@ -68,6 +70,40 @@ async fn main() -> Result<()> {
let mut job = envelope.job();

match job.instruction() {
GetProjects() => {
// get the list of projects from the cluster
tracing::info!("Getting list of projects");
job = job.completed("Projects retrieved".to_string())?;
},
GetUsers(project) => {
// get the list of users from the cluster
tracing::info!("Getting list of users in project {}", project);
job = job.completed("Users retrieved".to_string())?;
},
AddProject(project) => {
// add the project to the cluster
tracing::info!("Adding project to cluster: {}", project);
let mapping = create_project(me.name(), &project).await?;

job = job.running(Some("Step 1/3: Project created".to_string()))?;
job = job.update(&sender).await?;

// now create the project directories
create_project_directories(me.name(), &mapping).await?;

job = job.running(Some("Step 2/3: Directories created".to_string()))?;
job = job.update(&sender).await?;

// and finally add the project to the job scheduler
add_project_to_scheduler(me.name(), &project, &mapping).await?;

job = job.completed(mapping)?;
},
RemoveProject(project) => {
// remove the project from the cluster
tracing::info!("Removing project from cluster: {}", project);
job = job.completed("Project removed".to_string())?;
},
AddUser(user) => {
// add the user to the cluster
tracing::info!("Adding user to cluster: {}", user);
Expand All @@ -77,7 +113,7 @@ async fn main() -> Result<()> {
job = job.update(&sender).await?;

// now create their home directories
let homedir = create_directories(me.name(), &mapping).await?;
let homedir = create_user_directories(me.name(), &mapping).await?;

job = job.running(Some("Step 2/3: Directories created".to_string()))?;
job = job.update(&sender).await?;
Expand All @@ -86,14 +122,14 @@ async fn main() -> Result<()> {
update_homedir(me.name(), &user, &homedir).await?;

// and finally add the user to the job scheduler
add_to_scheduler(me.name(), &user, &mapping).await?;
add_user_to_scheduler(me.name(), &user, &mapping).await?;

job = job.completed(mapping)?;
}
RemoveUser(user) => {
// remove the user from the cluster
tracing::info!("Removing user from cluster: {}", user);
job = job.completed("User removed")?;
job = job.completed("User removed".to_string())?;
}
_ => {
tracing::error!("Unknown instruction: {:?}", job.instruction());
Expand All @@ -113,6 +149,43 @@ async fn main() -> Result<()> {
Ok(())
}

async fn create_project(me: &str, project: &ProjectIdentifier) -> Result<ProjectMapping, Error> {
// find the Account agent
match agent::account(30).await {
Some(account) => {
// send the add_job to the account agent
let job = Job::parse(
&format!("{}.{} add_project {}", me, account.name(), project),
false,
)?
.put(&account)
.await?;

// Wait for the add_job to complete
let result = job.wait().await?.result::<ProjectMapping>()?;

match result {
Some(mapping) => {
tracing::info!("Project added to account agent: {:?}", mapping);
Ok(mapping)
}
None => {
tracing::error!("Error creating the project group: {:?}", job);
Err(Error::Call(
format!("Error creating the project group: {:?}", job).to_string(),
))
}
}
}
None => {
tracing::error!("No account agent found");
Err(Error::MissingAgent(
"Cannot run the job because there is no account agent".to_string(),
))
}
}
}

async fn create_account(me: &str, user: &UserIdentifier) -> Result<UserMapping, Error> {
// find the Account agent
match agent::account(30).await {
Expand Down Expand Up @@ -150,7 +223,44 @@ async fn create_account(me: &str, user: &UserIdentifier) -> Result<UserMapping,
}
}

async fn create_directories(me: &str, mapping: &UserMapping) -> Result<String, Error> {
async fn create_project_directories(me: &str, mapping: &ProjectMapping) -> Result<String, Error> {
// find the Filesystem agent
match agent::filesystem(30).await {
Some(filesystem) => {
// send the add_job to the filesystem agent
let job = Job::parse(
&format!("{}.{} add_local_project {}", me, filesystem.name(), mapping),
false,
)?
.put(&filesystem)
.await?;

// Wait for the add_job to complete
let result = job.wait().await?.result::<String>()?;

match result {
Some(homedir) => {
tracing::info!("Directories created for project: {:?}", mapping);
Ok(homedir)
}
None => {
tracing::error!("Error creating the project directories: {:?}", job);
Err(Error::Call(
format!("Error creating the project directories: {:?}", job).to_string(),
))
}
}
}
None => {
tracing::error!("No filesystem agent found");
Err(Error::MissingAgent(
"Cannot run the job because there is no filesystem agent".to_string(),
))
}
}
}

async fn create_user_directories(me: &str, mapping: &UserMapping) -> Result<String, Error> {
// find the Filesystem agent
match agent::filesystem(30).await {
Some(filesystem) => {
Expand Down Expand Up @@ -230,7 +340,49 @@ async fn update_homedir(me: &str, user: &UserIdentifier, homedir: &str) -> Resul
}
}

async fn add_to_scheduler(
async fn add_project_to_scheduler(
me: &str,
project: &ProjectIdentifier,
mapping: &ProjectMapping,
) -> Result<(), Error> {
// find the Scheduler agent
match agent::scheduler(30).await {
Some(scheduler) => {
// send the add_job to the scheduler agent
let job = Job::parse(
&format!("{}.{} add_local_project {}", me, scheduler.name(), mapping),
false,
)?
.put(&scheduler)
.await?;

// Wait for the add_job to complete
let result = job.wait().await?.result::<String>()?;

match result {
Some(_) => {
tracing::info!("Project {} added to scheduler", project);
Ok(())
}
None => {
tracing::error!("Error adding the project to the scheduler: {:?}", project);
Err(Error::Call(
format!("Error adding the project to the scheduler: {:?}", project)
.to_string(),
))
}
}
}
None => {
tracing::error!("No scheduler agent found");
Err(Error::MissingAgent(
"Cannot run the job because there is no scheduler agent".to_string(),
))
}
}
}

async fn add_user_to_scheduler(
me: &str,
user: &UserIdentifier,
mapping: &UserMapping,
Expand Down
4 changes: 2 additions & 2 deletions docs/cmdline/cluster/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async_runnable! {

tracing::info!("Here we would implement the business logic to add the user to the cluster");

job = job.completed("account created")?;
job = job.completed("account created".to_string())?;
}
RemoveUser(user) => {
// remove the user from the cluster
Expand All @@ -72,7 +72,7 @@ async_runnable! {
job = job.errored(&format!("You are not allowed to remove the account for {:?}",
user.username()))?;
} else {
job = job.completed("account removed")?;
job = job.completed("account removed".to_string())?;
}
}
_ => {
Expand Down
4 changes: 2 additions & 2 deletions docs/job/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ async_runnable! {

tracing::info!("Here we would implement the business logic to add the user to the cluster");

job = job.completed("account created")?;
job = job.completed("account created".to_string())?;
}
RemoveUser(user) => {
// remove the user from the cluster
Expand All @@ -173,7 +173,7 @@ async_runnable! {
job = job.errored(&format!("You are not allowed to remove the account for {:?}",
user.username()))?;
} else {
job = job.completed("account removed")?;
job = job.completed("account removed".to_string())?;
}
}
_ => {
Expand Down
Loading

0 comments on commit 8de1c11

Please sign in to comment.