Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ufm rust client #119

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions plugins/ufm_rust_client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Cargo
# will have compiled files and executables
/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk


# Added by cargo

/target
/Cargo.lock
/.idea/
8 changes: 8 additions & 0 deletions plugins/ufm_rust_client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[workspace]

members = [
"cli",
"client",
]


71 changes: 71 additions & 0 deletions plugins/ufm_rust_client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
## *UFM rust client*
The rust client of UFM

### *Build*
To install [rust](https://www.rust-lang.org/tools/install) on the machine.

```
cargo build
```

### *Usage*

Use the following syntax to run `ufmcli` commands from your terminal window:
```
ufmcli [flags] [command] [parameters]
```

where flags, command, and parameters are:
* `flags`: Specifies optional flags. For example, you can use the `--ufm-address` or `--ufm-token` flags to specify the address and token of the UFM server.
* `command`: Specifies the operation that you want to perform on UFM, for example `view`, `list`, `delete`, `create`.
* `parameters`: Specifies the parameters for command, for example `-p` or `--pkey` to specify the pkey for the partition.

`ufmcli` needs to know the UFM server address and authentication(username/password or token) to access UFM server.

There are two ways to set the UFM server address and authentication for `ufmcli` command.
* Environment: Set environment `UFM_ADDRESS` for the UFM server address, for example `export UFM_ADDRESS=http://hpc-cloud-gw.mtr.labs.mlnx:4402`. Set environment `UFM_TOKEN` or `UFM_USERNAME`, `UFM_PASSWORD` for the authentication.
* Flag: Specifies the flags in the `ufmcli` command, you can use `--ufm-address` to specify the UFM address and `--ufm-token` or `--ufm-username`, `--ufm-password` to specify the authentication.


#### *Version*
```
./ufmcli version
6.11.1-2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need hardcoded UFM version here?
can we support regex or $UFM_VERSION > 6.11.1-2 != 6.12.1-5 e.t.c.?

```
#### *Create a Partition Key*
```
./ufmcli create --pkey 5 --mtu 2 --membership full --service-level 0 --rate-limit 2.5 --guids 0011223344560200 --guids 1070fd0300176625 --guids 0011223344560201
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can GUIDs be part of external configuration file and not hardcoded ?

```

#### *View a Partition Key*
```
./ufmcli view --pkey 0x5
Name : api_pkey_0x5
Pkey : 0x5
IPoIB : false
MTU : 2
Rate Limit : 2.5
Service Level : 0
Ports :
GUID ParentGUID PortType SystemID LID SystemName LogState Name
0011223344560200 1070fd0300176624 virtual 1070fd0300176624 7 hpc-cloud01 Active
1070fd0300176625 physical 1070fd0300176624 4 hpc-cloud01 Active 1070fd0300176625_2
0011223344560201 65535 Unknown

```

#### *List Partition Keys*
```
./ufmcli list
Name Pkey IPoIB MTU Rate Level
api_pkey_0x5 0x5 false 2 2.5 0
api_pkey_0x2 0x2 false 2 2.5 0
management 0x7fff true 2 2.5 0
api_pkey_0x1 0x1 false 2 2.5 0
api_pkey_0x4 0x4 false 2 2.5 0
```

#### *Delete a Partition Key*
```
./ufmcli delete --pkey 0x2
```
13 changes: 13 additions & 0 deletions plugins/ufm_rust_client/cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "ufmcli"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ufmclient = { path = "../client" }
tokio = { version = "1", features = ["full"] }
clap = { version = "4.1", features = ["derive", "env"] }
env_logger = { version = "0.10" }

55 changes: 55 additions & 0 deletions plugins/ufm_rust_client/cli/src/create.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright © 2013-2022 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2023

*
* This software product is a proprietary product of Nvidia Corporation and its affiliates
* (the "Company") and all right, title, and interest in and to the software product,
* including all associated intellectual property rights, are and shall
* remain exclusively with the Company.
*
* This software product is governed by the End User License Agreement
* provided with the software product.
*/


use ufmclient::{
Partition, PartitionKey, PartitionQoS, PortConfig, PortMembership, UFMConfig, UFMError,
};

pub struct CreateOptions {
pub pkey: String,
pub mtu: u16,
pub ipoib: bool,
pub index0: bool,
pub membership: String,
pub service_level: u8,
pub rate_limit: f64,
pub guids: Vec<String>,
}

pub async fn run(conf: UFMConfig, opt: &CreateOptions) -> Result<(), UFMError> {
let ufm = ufmclient::connect(conf)?;

let mut pbs = vec![];
for g in &opt.guids {
pbs.push(PortConfig {
guid: g.to_string(),
index0: opt.index0,
membership: PortMembership::try_from(opt.membership.clone())?,
})
}

let p = Partition {
name: "".to_string(),
pkey: PartitionKey::try_from(opt.pkey.clone())?,
ipoib: opt.ipoib,
qos: PartitionQoS {
mtu_limit: opt.mtu,
service_level: opt.service_level,
rate_limit: opt.rate_limit,
},
};

ufm.bind_ports(p, pbs).await?;

Ok(())
}
20 changes: 20 additions & 0 deletions plugins/ufm_rust_client/cli/src/delete.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright © 2013-2022 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2023

*
* This software product is a proprietary product of Nvidia Corporation and its affiliates
* (the "Company") and all right, title, and interest in and to the software product,
* including all associated intellectual property rights, are and shall
* remain exclusively with the Company.
*
* This software product is governed by the End User License Agreement
* provided with the software product.
*/

use ufmclient::{UFMConfig, UFMError};

pub async fn run(conf: UFMConfig, pkey: &String) -> Result<(), UFMError> {
let ufm = ufmclient::connect(conf)?;
ufm.delete_partition(pkey).await?;

Ok(())
}
37 changes: 37 additions & 0 deletions plugins/ufm_rust_client/cli/src/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright © 2013-2022 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
*
* This software product is a proprietary product of Nvidia Corporation and its affiliates
* (the "Company") and all right, title, and interest in and to the software product,
* including all associated intellectual property rights, are and shall
* remain exclusively with the Company.
*
* This software product is governed by the End User License Agreement
* provided with the software product.
*/

use ufmclient::{UFMConfig, UFMError};

pub async fn run(conf: UFMConfig) -> Result<(), UFMError> {
let ufm = ufmclient::connect(conf)?;
let ps = ufm.list_partition().await?;

println!(
"{:<15}{:<10}{:<10}{:<10}{:<10}{:<10}",
"Name", "Pkey", "IPoIB", "MTU", "Rate", "Level"
);

for p in ps {
println!(
"{:<15}{:<10}{:<10}{:<10}{:<10}{:<10}",
p.name,
p.pkey.to_string(),
p.ipoib,
p.qos.mtu_limit,
p.qos.rate_limit,
p.qos.service_level
)
}

Ok(())
}
138 changes: 138 additions & 0 deletions plugins/ufm_rust_client/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright © 2013-2022 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
*
* This software product is a proprietary product of Nvidia Corporation and its affiliates
* (the "Company") and all right, title, and interest in and to the software product,
* including all associated intellectual property rights, are and shall
* remain exclusively with the Company.
*
* This software product is governed by the End User License Agreement
* provided with the software product.
*/

use clap::{Parser, Subcommand};
use ufmclient::{UFMConfig, UFMError};

mod create;
mod delete;
mod list;
mod version;
mod view;

#[derive(Parser)]
#[command(name = "ufm")]
#[command(version = "0.1.0")]
#[command(about = "UFM command line", long_about = None)]
struct Options {
#[clap(long, env = "UFM_ADDRESS")]
ufm_address: Option<String>,
#[clap(long, env = "UFM_USERNAME")]
ufm_username: Option<String>,
#[clap(long, env = "UFM_PASSWORD")]
ufm_password: Option<String>,
#[clap(long, env = "UFM_TOKEN")]
ufm_token: Option<String>,
#[clap(subcommand)]
command: Option<Commands>,
}

#[derive(Subcommand)]
enum Commands {
/// View the detail of the partition
View {
/// The pkey of the partition to view
#[arg(short, long)]
pkey: String,
},
/// List all partitions
List,
/// Get the version of UFM
Version,
/// Delete the partition
Delete {
/// The pkey of the partition to delete
#[arg(short, long)]
pkey: String,
},
/// Create a partition
Create {
/// The pkey for the new partition
#[arg(short, long)]
pkey: String,
/// The MTU of the new partition
#[arg(long, default_value_t = 2048)]
mtu: u16,
/// The IPOverIB of the new partition
#[arg(long, default_value_t = true)]
ipoib: bool,
/// The Index0 of the new partition
#[arg(long, default_value_t = true)]
index0: bool,
/// The Membership of the new partition
#[arg(short, long, default_value_t = String::from("full"))]
membership: String,
/// The ServiceLevel of the new partition
#[arg(short, long, default_value_t = 0)]
service_level: u8,
/// The RateLimit of the new partition
#[arg(short, long, default_value_t = 100.0)]
rate_limit: f64,
/// The GUIDs of the new partition
#[arg(short, long)]
guids: Vec<String>,
},
}

#[tokio::main]
async fn main() -> Result<(), UFMError> {
env_logger::init();

let opt: Options = Options::parse();

let conf = load_conf(&opt);
match &opt.command {
Some(Commands::Delete { pkey }) => delete::run(conf, pkey).await?,
Some(Commands::Version) => version::run(conf).await?,
Some(Commands::List) => list::run(conf).await?,
Some(Commands::View { pkey }) => view::run(conf, pkey).await?,
Some(Commands::Create {
pkey,
mtu,
ipoib,
index0,
membership,
service_level,
rate_limit,
guids,
}) => {
let opt = create::CreateOptions {
pkey: pkey.to_string(),
mtu: *mtu,
ipoib: *ipoib,
index0: *index0,
membership: membership.to_string(),
service_level: *service_level,
rate_limit: *rate_limit,
guids: guids.to_vec(),
};
create::run(conf, &opt).await?
}
None => {}
};

Ok(())
}

fn load_conf(opt: &Options) -> UFMConfig {
let ufm_address = match opt.ufm_address.clone() {
Some(s) => s,
None => panic!("UFM_ADDRESS environment or ufm_address parameter not found"),
};

UFMConfig {
address: ufm_address,
username: opt.ufm_username.clone(),
password: opt.ufm_password.clone(),
token: opt.ufm_token.clone(),
}
}
22 changes: 22 additions & 0 deletions plugins/ufm_rust_client/cli/src/version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright © 2013-2022 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
*
* This software product is a proprietary product of Nvidia Corporation and its affiliates
* (the "Company") and all right, title, and interest in and to the software product,
* including all associated intellectual property rights, are and shall
* remain exclusively with the Company.
*
* This software product is governed by the End User License Agreement
* provided with the software product.
*/

use ufmclient::{UFMConfig, UFMError};

pub async fn run(conf: UFMConfig) -> Result<(), UFMError> {
let ufm = ufmclient::connect(conf)?;
let v = ufm.version().await?;

println!("{}", v);

Ok(())
}
Loading