10 Commits

Author SHA1 Message Date
GW_MC
c65dc3af47 feat: Basic agent-client service
Some checks failed
Test / test-frontend (pull_request) Successful in 27s
Test / frontend-build (pull_request) Successful in 33s
Verify / verify-openapi-spec (pull_request) Successful in 7s
Verify / verify-generated-agent-code (pull_request) Successful in 1m7s
Verify / verify-generated-database-code (pull_request) Successful in 2m14s
Verify / verify-frontend-api-client (pull_request) Successful in 6s
Test / lint-crates (pull_request) Failing after 1m28s
Test / test-crates (pull_request) Successful in 2m40s
Test / lint-frontend (pull_request) Successful in 29s
2025-12-28 17:53:27 +08:00
GW_MC
6f395ed1ae rename workflows jobs 2025-12-28 16:42:12 +08:00
GW_MC
e6e85564e7 fix: incorrect pnpm cache
All checks were successful
Test / test-frontend (pull_request) Successful in 1m17s
Test / lint-frontend (pull_request) Successful in 1m19s
Test / frontend-build (pull_request) Successful in 1m55s
Verify / verify-openapi-spec (pull_request) Successful in 31s
Verify / verify-generated-agent-code (pull_request) Successful in 2m54s
Verify / verify-generated-code (pull_request) Successful in 3m57s
Verify / verify-frontend-api-client (pull_request) Successful in 8s
Test / lint (pull_request) Successful in 1m25s
Test / test (pull_request) Successful in 3m26s
2025-12-28 16:29:31 +08:00
GW_MC
c7a090f78a fix: frontend deps not installed 2025-12-28 16:23:10 +08:00
GW_MC
8cc2775fe4 feat: auto format generated code, and ignore clippy lint in agent-client 2025-12-28 16:22:41 +08:00
GW_MC
0b64538754 added verify for untracked generated files 2025-12-28 15:56:04 +08:00
GW_MC
8009ca20ff feat: added verify generated agent code in action workflows 2025-12-28 15:55:30 +08:00
GW_MC
7a5b9471e0 feat: added agent rust client generation 2025-12-28 15:16:47 +08:00
GW_MC
bb55e37b49 feat: added openapi generation for agent 2025-12-28 15:15:42 +08:00
9a264a61ac Merge pull request 'feature/agent' (#11) from feature/agent into master
All checks were successful
Test / test-frontend (push) Successful in 20s
Test / lint-frontend (push) Successful in 24s
Verify / verify-openapi-spec (push) Successful in 4s
Test / frontend-build (push) Successful in 29s
Verify / verify-frontend-api-client (push) Successful in 5s
Test / test (push) Successful in 53s
Verify / verify-generated-code (push) Successful in 1m6s
Test / lint (push) Successful in 1m10s
Reviewed-on: #11
2025-12-22 18:29:26 +08:00
44 changed files with 4564 additions and 1404 deletions

View File

@@ -12,11 +12,8 @@ on:
jobs: jobs:
# setup is now handled by a composite action used by downstream jobs to keep
# the workflow DRY. The composite action performs checkout, cache restore and
# toolchain setup.
test: test-crates:
needs: frontend-build needs: frontend-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -39,7 +36,7 @@ jobs:
- name: Run tests - name: Run tests
run: cargo test --all-features run: cargo test --all-features
lint: lint-crates:
needs: frontend-build needs: frontend-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -83,7 +80,7 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: apps/frontend/pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml
- name: Install frontend dependencies - name: Install frontend dependencies
run: | run: |
@@ -114,7 +111,7 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: apps/frontend/pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml
- name: Install frontend dependencies - name: Install frontend dependencies
run: | run: |
@@ -142,12 +139,12 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: apps/frontend/pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml
- name: Install frontend dependencies - name: Install frontend dependencies
run: | run: |
cd apps/frontend cd apps/frontend
pnpm install pnpm install --frozen-lockfile
- name: Build frontend - name: Build frontend
run: | run: |

View File

@@ -11,11 +11,8 @@ on:
jobs: jobs:
# setup is now handled by a composite action used by downstream jobs to keep
# the workflow DRY. The composite action performs checkout, cache restore and
# toolchain setup.
verify-generated-code: verify-generated-database-code:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
@@ -32,14 +29,62 @@ jobs:
cargo run -- db:migrate_and_generate --output-path ../../public/database/src/generated/entities cargo run -- db:migrate_and_generate --output-path ../../public/database/src/generated/entities
- name: Check for uncommitted changes in /generated/ - name: Check for uncommitted changes in /generated/
run: | run: |
if [[ -n $(git status --porcelain | grep '^ M .*\/generated\/') ]]; then if [[ -n $(git status --porcelain --untracked-files=all | grep '/generated/') ]]; then
echo "Generated code is not up to date. Please run the code generation locally and commit the changes." echo "Generated code is not up to date. Please run the code generation locally and commit the changes."
git status --porcelain | grep '^ M .*\/generated\/' git status --porcelain --untracked-files=all | grep '/generated/'
exit 1 exit 1
else else
echo "Generated code is up to date." echo "Generated code is up to date."
fi fi
verify-generated-agent-code:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
- name: Setup Rust, checkout and restore caches
uses: ./.github/actions/setup-rust
- name: Setup PNPM
uses: pnpm/action-setup@v4
with:
version: 10
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
cache-dependency-path: pnpm-lock.yaml
- name: Install root dependencies
run: |
pnpm install --frozen-lockfile
- name: generate agent client code
run: |
pnpm just generate-agent-client
- name: Check for uncommitted changes in agent client code
run: |
if [[ -n $(git status --porcelain --untracked-files=all | grep 'public/agent-client/') ]]; then
echo "Agent client code is not up to date. Please run the agent client code generation locally and commit the changes."
git status --porcelain --untracked-files=all | grep 'public/agent-client/'
exit 1
else
echo "Agent client code is up to date."
fi
verify-openapi-spec: verify-openapi-spec:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -99,9 +144,9 @@ jobs:
- name: Check for uncommitted changes in swagger.json - name: Check for uncommitted changes in swagger.json
if: steps.check_changes.outputs.changed == 'true' if: steps.check_changes.outputs.changed == 'true'
run: | run: |
if [[ -n $(git status --porcelain | grep '^ M apps/api/swagger.json') ]]; then if [[ -n $(git status --porcelain --untracked-files=all | grep 'apps/api/swagger.json') ]]; then
echo "OpenAPI spec is not up to date. Please run the OpenAPI generation locally and commit the changes." echo "OpenAPI spec is not up to date. Please run the OpenAPI generation locally and commit the changes."
git status --porcelain | grep '^ M apps/api/swagger.json' git status --porcelain --untracked-files=all | grep 'apps/api/swagger.json'
exit 1 exit 1
else else
echo "OpenAPI spec is up to date." echo "OpenAPI spec is up to date."
@@ -165,7 +210,7 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: apps/frontend/pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml
- name: Install frontend dependencies - name: Install frontend dependencies
if: steps.check_swagger_changes.outputs.changed == 'true' if: steps.check_swagger_changes.outputs.changed == 'true'
@@ -182,9 +227,9 @@ jobs:
- name: Check for uncommitted changes in frontend API client - name: Check for uncommitted changes in frontend API client
if: steps.check_swagger_changes.outputs.changed == 'true' if: steps.check_swagger_changes.outputs.changed == 'true'
run: | run: |
if [[ -n $(git status --porcelain | grep '^ M apps/frontend/app/generated/api-client') ]]; then if [[ -n $(git status --porcelain --untracked-files=all | grep 'apps/frontend/app/generated/api-client') ]]; then
echo "Frontend API client is not up to date. Please run the API client generation locally and commit the changes." echo "Frontend API client is not up to date. Please run the API client generation locally and commit the changes."
git status --porcelain | grep '^ M apps/frontend/app/generated/api-client' git status --porcelain --untracked-files=all | grep 'apps/frontend/app/generated/api-client'
exit 1 exit 1
else else
echo "Frontend API client is up to date." echo "Frontend API client is up to date."

2
.gitignore vendored
View File

@@ -27,3 +27,5 @@ target
.env.generated .env.generated
generated-config.yaml generated-config.yaml
node_modules/

505
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@ members = [
"apps/container", "apps/container",
"apps/cli", "apps/cli",
"apps/agent", "apps/agent",
"public/agent-client",
"public/shared", "public/shared",
"public/database", "public/database",
"public/migration" "public/migration"

View File

@@ -13,3 +13,4 @@ serde = { version = "1.0.228", features = ["std", "derive"] }
tokio-cron-scheduler = { version = "0.15.1", features = ["signal"] } tokio-cron-scheduler = { version = "0.15.1", features = ["signal"] }
clap = { version = "4", features = ["derive", "env"] } clap = { version = "4", features = ["derive", "env"] }
nix = { version = "0.30.1", features = ["user", "fs"] } nix = { version = "0.30.1", features = ["user", "fs"] }
utoipa = { version = "5.4.0", features = ["macros", "axum_extras", "chrono", "decimal", "uuid", "time", "openapi_extensions"] }

View File

@@ -1,6 +1,7 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
mod commands; mod commands;
mod openapi;
mod routes; mod routes;
use axum::routing::get; use axum::routing::get;
@@ -13,6 +14,7 @@ use tokio::net::UnixListener;
use tracing::{error, info, warn}; use tracing::{error, info, warn};
use crate::commands::NginxService; use crate::commands::NginxService;
use crate::openapi::{GenerateOpenapiArgs, generate_openapi_doc};
use crate::routes::{status, validate, validate_and_reload, write_config}; use crate::routes::{status, validate, validate_and_reload, write_config};
const SOCK_ENV: &str = "YANPM_AGENT_SOCK"; const SOCK_ENV: &str = "YANPM_AGENT_SOCK";
@@ -43,6 +45,19 @@ struct Args {
/// GID to set on the unix socket, default: current user's primary group /// GID to set on the unix socket, default: current user's primary group
#[arg(long, default_value_t = String::from(SOCK_GID_DEFAULT), env = SOCK_GID_ENV)] #[arg(long, default_value_t = String::from(SOCK_GID_DEFAULT), env = SOCK_GID_ENV)]
sock_gid: String, sock_gid: String,
#[command(subcommand)]
command: Option<SubCommand>,
}
#[derive(clap::Subcommand, Debug)]
pub enum SubCommand {
/// Generate OpenAPI spec to file or stdout
GenerateOpenapi {
/// Output file path.
#[arg(short = 'o', long)]
output: String,
},
} }
#[tokio::main] #[tokio::main]
@@ -59,6 +74,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let args = Args::parse(); let args = Args::parse();
if let Some(cmd) = &args.command {
match cmd {
SubCommand::GenerateOpenapi { output } => {
generate_openapi_doc(&GenerateOpenapiArgs {
output: output.clone(),
})
.await?;
return Ok(());
}
}
}
let (sock, nginx_config_dir, sock_perm, sock_gid) = get_args(&args).await?; let (sock, nginx_config_dir, sock_perm, sock_gid) = get_args(&args).await?;
let path = PathBuf::from(&sock); let path = PathBuf::from(&sock);

45
apps/agent/src/openapi.rs Normal file
View File

@@ -0,0 +1,45 @@
use tracing::info;
use utoipa::OpenApi;
pub mod tag {
/// nginx
pub const NGINX_TAG: &str = "Nginx Agent";
}
#[derive(utoipa::OpenApi)]
#[openapi(
paths(
crate::routes::status,
crate::routes::validate,
crate::routes::validate_and_reload,
crate::routes::write_config,
),
components(
schemas(crate::routes::StatusResp),
schemas(crate::routes::ValidateAndReloadResp),
schemas(crate::routes::ValidateBody),
schemas(crate::routes::WriteConfigBody),
schemas(crate::routes::ValidateAndReloadBody),
),
tags(
(name = tag::NGINX_TAG, description = "Nginx Agent API"),
)
)]
struct ApiDoc;
pub struct GenerateOpenapiArgs {
pub output: String,
}
pub async fn generate_openapi_doc(
args: &GenerateOpenapiArgs,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
info!("Generating OpenAPI documentation...");
let doc = ApiDoc::openapi();
let json = doc
.to_pretty_json()
.expect("Failed to serialize OpenAPI doc to JSON");
std::fs::write(&args.output, json).expect("Failed to write OpenAPI doc to file");
info!("OpenAPI documentation generated at {}", args.output);
Ok(())
}

View File

@@ -9,28 +9,46 @@ use tracing::warn;
use crate::commands::NginxService; use crate::commands::NginxService;
#[derive(Serialize)] #[derive(Serialize, utoipa::ToSchema)]
pub struct StatusResp { pub struct StatusResp {
pub ok: bool, pub ok: bool,
} }
/// Health check endpoint
#[utoipa::path(
get,
path = "/status",
responses(
(status = 200, description = "Status response", body = StatusResp)
),
tag = crate::openapi::tag::NGINX_TAG
)]
pub async fn status() -> impl IntoResponse { pub async fn status() -> impl IntoResponse {
let resp = StatusResp { ok: true }; let resp = StatusResp { ok: true };
(axum::http::StatusCode::OK, axum::Json(resp)) (axum::http::StatusCode::OK, axum::Json(resp))
} }
#[derive(Serialize)] #[derive(Serialize, utoipa::ToSchema)]
pub struct ValidateAndReloadResp { pub struct ValidateAndReloadResp {
pub rc: i32, pub rc: i32,
pub ro: String, pub ro: String,
} }
#[derive(Deserialize)] #[derive(Deserialize, utoipa::ToSchema)]
pub struct ValidateBody { pub struct ValidateBody {
config_name: String, config_name: String,
timestamp: u64, timestamp: u64,
} }
#[utoipa::path(
post,
path = "/validate",
request_body = ValidateBody,
responses(
(status = 200, description = "Validation response", body = serde_json::Value)
),
tag = crate::openapi::tag::NGINX_TAG
)]
pub async fn validate( pub async fn validate(
State(nginx_controller): State<Arc<NginxService>>, State(nginx_controller): State<Arc<NginxService>>,
Json(payload): Json<Value>, Json(payload): Json<Value>,
@@ -57,12 +75,21 @@ pub async fn validate(
(axum::http::StatusCode::OK, axum::Json(resp)).into_response() (axum::http::StatusCode::OK, axum::Json(resp)).into_response()
} }
#[derive(Deserialize)] #[derive(Deserialize, utoipa::ToSchema)]
pub struct ValidateAndReloadBody { pub struct ValidateAndReloadBody {
config_name: String, config_name: String,
timestamp: u64, timestamp: u64,
} }
#[utoipa::path(
post,
path = "/validate_and_reload",
request_body = ValidateAndReloadBody,
responses(
(status = 200, description = "Validate and reload response", body = ValidateAndReloadResp)
),
tag = crate::openapi::tag::NGINX_TAG
)]
pub async fn validate_and_reload( pub async fn validate_and_reload(
State(nginx_controller): State<Arc<NginxService>>, State(nginx_controller): State<Arc<NginxService>>,
Json(payload): Json<Value>, Json(payload): Json<Value>,
@@ -96,13 +123,23 @@ pub async fn validate_and_reload(
(axum::http::StatusCode::OK, axum::Json(resp)).into_response() (axum::http::StatusCode::OK, axum::Json(resp)).into_response()
} }
#[derive(Deserialize)] #[derive(Deserialize, utoipa::ToSchema)]
pub struct WriteConfigBody { pub struct WriteConfigBody {
config_name: String, config_name: String,
timestamp: u64, timestamp: u64,
content: String, content: String,
} }
#[utoipa::path(
post,
path = "/write_config",
request_body = WriteConfigBody,
responses(
(status = 200, description = "Write config response"),
(status = 500, description = "Internal server error", body = serde_json::Value)
),
tag = crate::openapi::tag::NGINX_TAG
)]
pub async fn write_config( pub async fn write_config(
State(nginx_controller): State<Arc<NginxService>>, State(nginx_controller): State<Arc<NginxService>>,
Json(payload): Json<Value>, Json(payload): Json<Value>,

215
apps/agent/swagger.json Normal file
View File

@@ -0,0 +1,215 @@
{
"openapi": "3.1.0",
"info": {
"title": "yanpm-agent",
"description": "",
"license": {
"name": ""
},
"version": "0.1.0"
},
"paths": {
"/status": {
"get": {
"tags": [
"Nginx Agent"
],
"summary": "Health check endpoint",
"operationId": "status",
"responses": {
"200": {
"description": "Status response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StatusResp"
}
}
}
}
}
}
},
"/validate": {
"post": {
"tags": [
"Nginx Agent"
],
"operationId": "validate",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidateBody"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Validation response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
},
"/validate_and_reload": {
"post": {
"tags": [
"Nginx Agent"
],
"operationId": "validate_and_reload",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidateAndReloadBody"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Validate and reload response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ValidateAndReloadResp"
}
}
}
}
}
}
},
"/write_config": {
"post": {
"tags": [
"Nginx Agent"
],
"operationId": "write_config",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WriteConfigBody"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Write config response"
},
"500": {
"description": "Internal server error",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
}
},
"components": {
"schemas": {
"StatusResp": {
"type": "object",
"required": [
"ok"
],
"properties": {
"ok": {
"type": "boolean"
}
}
},
"ValidateAndReloadBody": {
"type": "object",
"required": [
"config_name",
"timestamp"
],
"properties": {
"config_name": {
"type": "string"
},
"timestamp": {
"type": "integer",
"format": "int64",
"minimum": 0
}
}
},
"ValidateAndReloadResp": {
"type": "object",
"required": [
"rc",
"ro"
],
"properties": {
"rc": {
"type": "integer",
"format": "int32"
},
"ro": {
"type": "string"
}
}
},
"ValidateBody": {
"type": "object",
"required": [
"config_name",
"timestamp"
],
"properties": {
"config_name": {
"type": "string"
},
"timestamp": {
"type": "integer",
"format": "int64",
"minimum": 0
}
}
},
"WriteConfigBody": {
"type": "object",
"required": [
"config_name",
"timestamp",
"content"
],
"properties": {
"config_name": {
"type": "string"
},
"content": {
"type": "string"
},
"timestamp": {
"type": "integer",
"format": "int64",
"minimum": 0
}
}
}
}
},
"tags": [
{
"name": "Nginx Agent",
"description": "Nginx Agent API"
}
]
}

View File

@@ -6,6 +6,7 @@ edition = "2024"
[dependencies] [dependencies]
database = { path = "../../public/database" } database = { path = "../../public/database" }
migration = { path = "../../public/migration" } migration = { path = "../../public/migration" }
agent_client = { path = "../../public/agent-client" }
axum = { version = "0.8.7", features = ["form", "http1", "http2", "json", "matched-path", "original-uri", "query", "tokio", "tower-log", "tracing", "macros"] } axum = { version = "0.8.7", features = ["form", "http1", "http2", "json", "matched-path", "original-uri", "query", "tokio", "tower-log", "tracing", "macros"] }
axum-extra = { version = "0.12.2", features = ["cookie"] } axum-extra = { version = "0.12.2", features = ["cookie"] }
@@ -28,4 +29,7 @@ argon2 = { version = "0.5.3", features = ["std"] }
jsonwebtoken = { version = "10.2.0", features = ["rust_crypto"] } jsonwebtoken = { version = "10.2.0", features = ["rust_crypto"] }
uuid = { version = "1.19.0", features = ["v4", "serde", "fast-rng"] } uuid = { version = "1.19.0", features = ["v4", "serde", "fast-rng"] }
tower-http = { version = "0.6.8", features = ["cors"] } tower-http = { version = "0.6.8", features = ["cors"] }
reqwest = { version = "^0.12", features = ["json", "multipart", "stream"] }
[dev-dependencies]
tempfile = "3"

View File

@@ -1,3 +1,4 @@
pub mod agent_client;
pub mod auth; pub mod auth;
pub mod server_state; pub mod server_state;
pub mod settings; pub mod settings;

View File

@@ -0,0 +1,92 @@
use std::sync::Arc;
use agent_client::apis::{ApiClient, configuration::Configuration};
pub struct AgentService {
client: Arc<ApiClient>,
}
impl AgentService {
pub fn new(config: impl Into<Arc<Configuration>>) -> Self {
let client = ApiClient::new(config.into());
AgentService {
client: Arc::new(client),
}
}
pub fn get_client(&self) -> Arc<ApiClient> {
Arc::clone(&self.client)
}
}
#[cfg(test)]
mod tests {
use super::*;
use agent_client::{
apis::{Api, nginx_agent_api::StatusSuccess},
models::StatusResp,
};
use axum::{http::StatusCode, response::Json};
use std::time::Duration;
use tempfile::tempdir;
use tokio::time::sleep;
#[test]
fn test_agent_service_creation() {
let config = Configuration::default();
let service = AgentService::new(config);
let client = service.get_client();
assert!(Arc::ptr_eq(&client, &service.client));
}
#[tokio::test]
async fn test_agent_socket_support() {
// create temporary socket path
let dir = tempdir().expect("Failed to create temp dir");
let socket_path = dir.path().join("agent.sock");
// create axum app with a simple /status route
let app = axum::Router::new().route(
"/status",
axum::routing::get(|| async {
let result: (StatusCode, StatusResp) = (StatusCode::OK, StatusResp { ok: true });
(result.0, Json(result.1))
}),
);
// bind tokio unix listener and serve in background
let listener =
tokio::net::UnixListener::bind(&socket_path).expect("Failed to bind to unix socket");
let server_fut = axum::serve::serve(listener, app);
let _srv = tokio::spawn(async move {
let _ = server_fut.await;
});
// give server a moment to start
sleep(Duration::from_millis(50)).await;
let client: ApiClient = ApiClient::new(Arc::new(Configuration {
base_path: "http://localhost".to_string(),
client: reqwest::Client::builder()
.unix_socket(socket_path.clone())
.build()
.expect("Failed to build reqwest client"),
..Default::default()
}));
let res = client
.nginx_agent_api()
.status()
.await
.expect("Failed to get status");
let body = res.entity.expect("Response entity is missing");
assert!(res.status.is_success());
if let StatusSuccess::Status200(body) = body {
assert!(body.ok);
} else {
panic!("Unexpected response body");
}
}
}

View File

@@ -50,9 +50,31 @@ generate-openapi:
# Generate API client for frontend # Generate API client for frontend
cd apps/frontend && \ cd apps/frontend && \
pnpm generate:openapi pnpm generate:openapi
# Generate API client for agent
cd apps/agent && \
cargo run -- generate-openapi --output swagger.json
generate-agent-client:
# Generate API client for agent
pnpm openapi-generator-cli generate \
-g rust --skip-validate-spec \
-o ./public/agent-client -i ./apps/agent/swagger.json \
--additional-properties=library=reqwest-trait \
--additional-properties=mockall=true \
--additional-properties=packageName=agent_client \
--additional-properties=packageVersion=0.1.0 \
--additional-properties=supportAsync=true \
--additional-properties=supportMultipleResponses=true \
--additional-properties=topLevelApiClient=true \
--additional-properties=useSingleRequestParameter=true
# format generated code
cd public/agent-client && \
cargo fmt
# append lint allows/forbids to the end of Cargo.toml to disable warnings in generated code and forbid unsafe code
cd public/agent-client && \
echo '\n[lints.clippy]\nall = "allow"\n[lints.rust]\nunsafe_code = "forbid"\n' >> Cargo.toml
generate-all: generate-entity generate-openapi generate-all: generate-entity generate-openapi generate-agent-client
build-frontend: build-frontend:
# build frontend assets # build frontend assets

7
openapitools.json Normal file
View File

@@ -0,0 +1,7 @@
{
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "7.18.0"
}
}

6
package.json Normal file
View File

@@ -0,0 +1,6 @@
{
"devDependencies": {
"@openapitools/openapi-generator-cli": "^2.26.0",
"rust-just": "^1.44.0"
}
}

File diff suppressed because it is too large Load Diff

7
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,7 @@
packages:
- apps/frontend
onlyBuiltDependencies:
- '@nestjs/core'
- '@openapitools/openapi-generator-cli'
- esbuild

3
public/agent-client/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/target/
**/*.rs.bk
Cargo.lock

View File

@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@@ -0,0 +1,21 @@
.gitignore
.travis.yml
Cargo.toml
README.md
docs/NginxAgentApi.md
docs/StatusResp.md
docs/ValidateAndReloadBody.md
docs/ValidateAndReloadResp.md
docs/ValidateBody.md
docs/WriteConfigBody.md
git_push.sh
src/apis/configuration.rs
src/apis/mod.rs
src/apis/nginx_agent_api.rs
src/lib.rs
src/models/mod.rs
src/models/status_resp.rs
src/models/validate_and_reload_body.rs
src/models/validate_and_reload_resp.rs
src/models/validate_body.rs
src/models/write_config_body.rs

View File

@@ -0,0 +1 @@
7.18.0

View File

@@ -0,0 +1 @@
language: rust

View File

@@ -0,0 +1,27 @@
[package]
name = "agent_client"
version = "0.1.0"
authors = ["OpenAPI Generator team and contributors"]
description = "No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)"
license = ""
edition = "2021"
[dependencies]
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0"
serde_repr = "^0.1"
url = "^2.5"
async-trait = "^0.1"
reqwest = { version = "^0.12", default-features = false, features = ["json", "multipart", "stream"] }
mockall = { version = "^0.13", optional = true}
[features]
default = ["native-tls"]
native-tls = ["reqwest/native-tls"]
rustls-tls = ["reqwest/rustls-tls"]
mockall = ["dep:mockall"]
[lints.clippy]
all = "allow"
[lints.rust]
unsafe_code = "forbid"

View File

@@ -0,0 +1,53 @@
# Rust API client for agent_client
No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
## Overview
This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://openapis.org) from a remote server, you can easily generate an API client.
- API version: 0.1.0
- Package version: 0.1.0
- Generator version: 7.18.0
- Build package: `org.openapitools.codegen.languages.RustClientCodegen`
## Installation
Put the package under your project folder in a directory named `agent_client` and add the following to `Cargo.toml` under `[dependencies]`:
```
agent_client = { path = "./agent_client" }
```
## Documentation for API Endpoints
All URIs are relative to *http://localhost*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*NginxAgentApi* | [**status**](docs/NginxAgentApi.md#status) | **GET** /status | Health check endpoint
*NginxAgentApi* | [**validate**](docs/NginxAgentApi.md#validate) | **POST** /validate |
*NginxAgentApi* | [**validate_and_reload**](docs/NginxAgentApi.md#validate_and_reload) | **POST** /validate_and_reload |
*NginxAgentApi* | [**write_config**](docs/NginxAgentApi.md#write_config) | **POST** /write_config |
## Documentation For Models
- [StatusResp](docs/StatusResp.md)
- [ValidateAndReloadBody](docs/ValidateAndReloadBody.md)
- [ValidateAndReloadResp](docs/ValidateAndReloadResp.md)
- [ValidateBody](docs/ValidateBody.md)
- [WriteConfigBody](docs/WriteConfigBody.md)
To get access to the crate's generated documentation, use:
```
cargo doc --open
```
## Author

View File

@@ -0,0 +1,121 @@
# \NginxAgentApi
All URIs are relative to *http://localhost*
Method | HTTP request | Description
------------- | ------------- | -------------
[**status**](NginxAgentApi.md#status) | **GET** /status | Health check endpoint
[**validate**](NginxAgentApi.md#validate) | **POST** /validate |
[**validate_and_reload**](NginxAgentApi.md#validate_and_reload) | **POST** /validate_and_reload |
[**write_config**](NginxAgentApi.md#write_config) | **POST** /write_config |
## status
> models::StatusResp status()
Health check endpoint
### Parameters
This endpoint does not need any parameter.
### Return type
[**models::StatusResp**](StatusResp.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
## validate
> serde_json::Value validate(validate_body)
### Parameters
Name | Type | Description | Required | Notes
------------- | ------------- | ------------- | ------------- | -------------
**validate_body** | [**ValidateBody**](ValidateBody.md) | | [required] |
### Return type
[**serde_json::Value**](serde_json::Value.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
## validate_and_reload
> models::ValidateAndReloadResp validate_and_reload(validate_and_reload_body)
### Parameters
Name | Type | Description | Required | Notes
------------- | ------------- | ------------- | ------------- | -------------
**validate_and_reload_body** | [**ValidateAndReloadBody**](ValidateAndReloadBody.md) | | [required] |
### Return type
[**models::ValidateAndReloadResp**](ValidateAndReloadResp.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
## write_config
> write_config(write_config_body)
### Parameters
Name | Type | Description | Required | Notes
------------- | ------------- | ------------- | ------------- | -------------
**write_config_body** | [**WriteConfigBody**](WriteConfigBody.md) | | [required] |
### Return type
(empty response body)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

View File

@@ -0,0 +1,11 @@
# StatusResp
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**ok** | **bool** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -0,0 +1,121 @@
# \TagNginxtagApi
All URIs are relative to *http://localhost*
Method | HTTP request | Description
------------- | ------------- | -------------
[**status**](TagNginxtagApi.md#status) | **GET** /status | Health check endpoint
[**validate**](TagNginxtagApi.md#validate) | **POST** /validate |
[**validate_and_reload**](TagNginxtagApi.md#validate_and_reload) | **POST** /validate_and_reload |
[**write_config**](TagNginxtagApi.md#write_config) | **POST** /write_config |
## status
> models::StatusResp status()
Health check endpoint
### Parameters
This endpoint does not need any parameter.
### Return type
[**models::StatusResp**](StatusResp.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
## validate
> serde_json::Value validate(validate_body)
### Parameters
Name | Type | Description | Required | Notes
------------- | ------------- | ------------- | ------------- | -------------
**validate_body** | [**ValidateBody**](ValidateBody.md) | | [required] |
### Return type
[**serde_json::Value**](serde_json::Value.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
## validate_and_reload
> models::ValidateAndReloadResp validate_and_reload(validate_and_reload_body)
### Parameters
Name | Type | Description | Required | Notes
------------- | ------------- | ------------- | ------------- | -------------
**validate_and_reload_body** | [**ValidateAndReloadBody**](ValidateAndReloadBody.md) | | [required] |
### Return type
[**models::ValidateAndReloadResp**](ValidateAndReloadResp.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
## write_config
> write_config(write_config_body)
### Parameters
Name | Type | Description | Required | Notes
------------- | ------------- | ------------- | ------------- | -------------
**write_config_body** | [**WriteConfigBody**](WriteConfigBody.md) | | [required] |
### Return type
(empty response body)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

View File

@@ -0,0 +1,12 @@
# ValidateAndReloadBody
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**config_name** | **String** | |
**timestamp** | **i64** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -0,0 +1,12 @@
# ValidateAndReloadResp
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**rc** | **i32** | |
**ro** | **String** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -0,0 +1,12 @@
# ValidateBody
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**config_name** | **String** | |
**timestamp** | **i64** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -0,0 +1,13 @@
# WriteConfigBody
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**config_name** | **String** | |
**content** | **String** | |
**timestamp** | **i64** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -0,0 +1,57 @@
#!/bin/sh
# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
#
# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com"
git_user_id=$1
git_repo_id=$2
release_note=$3
git_host=$4
if [ "$git_host" = "" ]; then
git_host="github.com"
echo "[INFO] No command line input provided. Set \$git_host to $git_host"
fi
if [ "$git_user_id" = "" ]; then
git_user_id="GIT_USER_ID"
echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id"
fi
if [ "$git_repo_id" = "" ]; then
git_repo_id="GIT_REPO_ID"
echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id"
fi
if [ "$release_note" = "" ]; then
release_note="Minor update"
echo "[INFO] No command line input provided. Set \$release_note to $release_note"
fi
# Initialize the local directory as a Git repository
git init
# Adds the files in the local repository and stages them for commit.
git add .
# Commits the tracked changes and prepares them to be pushed to a remote repository.
git commit -m "$release_note"
# Sets the new remote
git_remote=$(git remote)
if [ "$git_remote" = "" ]; then # git remote not defined
if [ "$GIT_TOKEN" = "" ]; then
echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment."
git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git
else
git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git
fi
fi
git pull origin master
# Pushes (Forces) the changes in the local repository up to the remote repository
echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git"
git push origin master 2>&1 | grep -v 'To https'

View File

@@ -0,0 +1,48 @@
/*
* yanpm-agent
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
* Generated by: https://openapi-generator.tech
*/
#[derive(Debug, Clone)]
pub struct Configuration {
pub base_path: String,
pub user_agent: Option<String>,
pub client: reqwest::Client,
pub basic_auth: Option<BasicAuth>,
pub oauth_access_token: Option<String>,
pub bearer_access_token: Option<String>,
pub api_key: Option<ApiKey>,
}
pub type BasicAuth = (String, Option<String>);
#[derive(Debug, Clone)]
pub struct ApiKey {
pub prefix: Option<String>,
pub key: String,
}
impl Configuration {
pub fn new() -> Configuration {
Configuration::default()
}
}
impl Default for Configuration {
fn default() -> Self {
Configuration {
base_path: "http://localhost".to_owned(),
user_agent: Some("OpenAPI-Generator/0.1.0/rust".to_owned()),
client: reqwest::Client::new(),
basic_auth: None,
oauth_access_token: None,
bearer_access_token: None,
api_key: None,
}
}
}

View File

@@ -0,0 +1,165 @@
use std::error;
use std::fmt;
#[derive(Debug, Clone)]
pub struct ResponseContent<T> {
pub status: reqwest::StatusCode,
pub content: String,
pub entity: Option<T>,
}
#[derive(Debug)]
pub enum Error<T> {
Reqwest(reqwest::Error),
Serde(serde_json::Error),
Io(std::io::Error),
ResponseError(ResponseContent<T>),
}
impl<T> fmt::Display for Error<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (module, e) = match self {
Error::Reqwest(e) => ("reqwest", e.to_string()),
Error::Serde(e) => ("serde", e.to_string()),
Error::Io(e) => ("IO", e.to_string()),
Error::ResponseError(e) => ("response", format!("status code {}", e.status)),
};
write!(f, "error in {}: {}", module, e)
}
}
impl<T: fmt::Debug> error::Error for Error<T> {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(match self {
Error::Reqwest(e) => e,
Error::Serde(e) => e,
Error::Io(e) => e,
Error::ResponseError(_) => return None,
})
}
}
impl<T> From<reqwest::Error> for Error<T> {
fn from(e: reqwest::Error) -> Self {
Error::Reqwest(e)
}
}
impl<T> From<serde_json::Error> for Error<T> {
fn from(e: serde_json::Error) -> Self {
Error::Serde(e)
}
}
impl<T> From<std::io::Error> for Error<T> {
fn from(e: std::io::Error) -> Self {
Error::Io(e)
}
}
pub fn urlencode<T: AsRef<str>>(s: T) -> String {
::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes()).collect()
}
pub fn parse_deep_object(prefix: &str, value: &serde_json::Value) -> Vec<(String, String)> {
if let serde_json::Value::Object(object) = value {
let mut params = vec![];
for (key, value) in object {
match value {
serde_json::Value::Object(_) => params.append(&mut parse_deep_object(
&format!("{}[{}]", prefix, key),
value,
)),
serde_json::Value::Array(array) => {
for (i, value) in array.iter().enumerate() {
params.append(&mut parse_deep_object(
&format!("{}[{}][{}]", prefix, key, i),
value,
));
}
}
serde_json::Value::String(s) => {
params.push((format!("{}[{}]", prefix, key), s.clone()))
}
_ => params.push((format!("{}[{}]", prefix, key), value.to_string())),
}
}
return params;
}
unimplemented!("Only objects are supported with style=deepObject")
}
/// Internal use only
/// A content type supported by this client.
#[allow(dead_code)]
enum ContentType {
Json,
Text,
Unsupported(String),
}
impl From<&str> for ContentType {
fn from(content_type: &str) -> Self {
if content_type.starts_with("application") && content_type.contains("json") {
return Self::Json;
} else if content_type.starts_with("text/plain") {
return Self::Text;
} else {
return Self::Unsupported(content_type.to_string());
}
}
}
pub mod nginx_agent_api;
pub mod configuration;
use std::sync::Arc;
pub trait Api {
fn nginx_agent_api(&self) -> &dyn nginx_agent_api::NginxAgentApi;
}
pub struct ApiClient {
nginx_agent_api: Box<dyn nginx_agent_api::NginxAgentApi>,
}
impl ApiClient {
pub fn new(configuration: Arc<configuration::Configuration>) -> Self {
Self {
nginx_agent_api: Box::new(nginx_agent_api::NginxAgentApiClient::new(
configuration.clone(),
)),
}
}
}
impl Api for ApiClient {
fn nginx_agent_api(&self) -> &dyn nginx_agent_api::NginxAgentApi {
self.nginx_agent_api.as_ref()
}
}
#[cfg(feature = "mockall")]
pub struct MockApiClient {
pub nginx_agent_api_mock: nginx_agent_api::MockNginxAgentApi,
}
#[cfg(feature = "mockall")]
impl MockApiClient {
pub fn new() -> Self {
Self {
nginx_agent_api_mock: nginx_agent_api::MockNginxAgentApi::new(),
}
}
}
#[cfg(feature = "mockall")]
impl Api for MockApiClient {
fn nginx_agent_api(&self) -> &dyn nginx_agent_api::NginxAgentApi {
&self.nginx_agent_api_mock
}
}

View File

@@ -0,0 +1,329 @@
/*
* yanpm-agent
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
* Generated by: https://openapi-generator.tech
*/
use super::{configuration, Error};
use crate::apis::ContentType;
use crate::{apis::ResponseContent, models};
use async_trait::async_trait;
#[cfg(feature = "mockall")]
use mockall::automock;
use reqwest;
use serde::{de::Error as _, Deserialize, Serialize};
use std::sync::Arc;
#[cfg_attr(feature = "mockall", automock)]
#[async_trait]
pub trait NginxAgentApi: Send + Sync {
/// GET /status
///
///
async fn status(&self) -> Result<ResponseContent<StatusSuccess>, Error<StatusError>>;
/// POST /validate
///
///
async fn validate(
&self,
params: ValidateParams,
) -> Result<ResponseContent<ValidateSuccess>, Error<ValidateError>>;
/// POST /validate_and_reload
///
///
async fn validate_and_reload(
&self,
params: ValidateAndReloadParams,
) -> Result<ResponseContent<ValidateAndReloadSuccess>, Error<ValidateAndReloadError>>;
/// POST /write_config
///
///
async fn write_config(
&self,
params: WriteConfigParams,
) -> Result<ResponseContent<WriteConfigSuccess>, Error<WriteConfigError>>;
}
pub struct NginxAgentApiClient {
configuration: Arc<configuration::Configuration>,
}
impl NginxAgentApiClient {
pub fn new(configuration: Arc<configuration::Configuration>) -> Self {
Self { configuration }
}
}
/// struct for passing parameters to the method [`NginxAgentApi::validate`]
#[derive(Clone, Debug)]
pub struct ValidateParams {
pub validate_body: models::ValidateBody,
}
/// struct for passing parameters to the method [`NginxAgentApi::validate_and_reload`]
#[derive(Clone, Debug)]
pub struct ValidateAndReloadParams {
pub validate_and_reload_body: models::ValidateAndReloadBody,
}
/// struct for passing parameters to the method [`NginxAgentApi::write_config`]
#[derive(Clone, Debug)]
pub struct WriteConfigParams {
pub write_config_body: models::WriteConfigBody,
}
#[async_trait]
impl NginxAgentApi for NginxAgentApiClient {
async fn status(&self) -> Result<ResponseContent<StatusSuccess>, Error<StatusError>> {
let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/status", local_var_configuration.base_path);
let mut local_var_req_builder =
local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder
.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;
let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<StatusSuccess> =
serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Ok(local_var_result)
} else {
let local_var_entity: Option<StatusError> =
serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error))
}
}
async fn validate(
&self,
params: ValidateParams,
) -> Result<ResponseContent<ValidateSuccess>, Error<ValidateError>> {
let ValidateParams { validate_body } = params;
let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/validate", local_var_configuration.base_path);
let mut local_var_req_builder =
local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder
.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
local_var_req_builder = local_var_req_builder.json(&validate_body);
let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;
let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<ValidateSuccess> =
serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Ok(local_var_result)
} else {
let local_var_entity: Option<ValidateError> =
serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error))
}
}
async fn validate_and_reload(
&self,
params: ValidateAndReloadParams,
) -> Result<ResponseContent<ValidateAndReloadSuccess>, Error<ValidateAndReloadError>> {
let ValidateAndReloadParams {
validate_and_reload_body,
} = params;
let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client;
let local_var_uri_str =
format!("{}/validate_and_reload", local_var_configuration.base_path);
let mut local_var_req_builder =
local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder
.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
local_var_req_builder = local_var_req_builder.json(&validate_and_reload_body);
let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;
let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<ValidateAndReloadSuccess> =
serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Ok(local_var_result)
} else {
let local_var_entity: Option<ValidateAndReloadError> =
serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error))
}
}
async fn write_config(
&self,
params: WriteConfigParams,
) -> Result<ResponseContent<WriteConfigSuccess>, Error<WriteConfigError>> {
let WriteConfigParams { write_config_body } = params;
let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/write_config", local_var_configuration.base_path);
let mut local_var_req_builder =
local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder
.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
local_var_req_builder = local_var_req_builder.json(&write_config_body);
let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;
let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<WriteConfigSuccess> =
serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Ok(local_var_result)
} else {
let local_var_entity: Option<WriteConfigError> =
serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error))
}
}
}
/// struct for typed successes of method [`NginxAgentApi::status`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum StatusSuccess {
Status200(models::StatusResp),
UnknownValue(serde_json::Value),
}
/// struct for typed successes of method [`NginxAgentApi::validate`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValidateSuccess {
Status200(serde_json::Value),
UnknownValue(serde_json::Value),
}
/// struct for typed successes of method [`NginxAgentApi::validate_and_reload`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValidateAndReloadSuccess {
Status200(models::ValidateAndReloadResp),
UnknownValue(serde_json::Value),
}
/// struct for typed successes of method [`NginxAgentApi::write_config`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WriteConfigSuccess {
Status200(),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`NginxAgentApi::status`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum StatusError {
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`NginxAgentApi::validate`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValidateError {
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`NginxAgentApi::validate_and_reload`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValidateAndReloadError {
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`NginxAgentApi::write_config`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WriteConfigError {
Status500(serde_json::Value),
UnknownValue(serde_json::Value),
}

View File

@@ -0,0 +1,280 @@
/*
* yanpm-agent
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
* Generated by: https://openapi-generator.tech
*/
use async_trait::async_trait;
#[cfg(feature = "mockall")]
use mockall::automock;
use reqwest;
use std::sync::Arc;
use serde::{Deserialize, Serialize, de::Error as _};
use crate::{apis::ResponseContent, models};
use super::{Error, configuration};
use crate::apis::ContentType;
#[cfg_attr(feature = "mockall", automock)]
#[async_trait]
pub trait TagNginxtagApi: Send + Sync {
/// GET /status
///
///
async fn status(&self, ) -> Result<ResponseContent<StatusSuccess>, Error<StatusError>>;
/// POST /validate
///
///
async fn validate(&self, params: ValidateParams ) -> Result<ResponseContent<ValidateSuccess>, Error<ValidateError>>;
/// POST /validate_and_reload
///
///
async fn validate_and_reload(&self, params: ValidateAndReloadParams ) -> Result<ResponseContent<ValidateAndReloadSuccess>, Error<ValidateAndReloadError>>;
/// POST /write_config
///
///
async fn write_config(&self, params: WriteConfigParams ) -> Result<ResponseContent<WriteConfigSuccess>, Error<WriteConfigError>>;
}
pub struct TagNginxtagApiClient {
configuration: Arc<configuration::Configuration>
}
impl TagNginxtagApiClient {
pub fn new(configuration: Arc<configuration::Configuration>) -> Self {
Self { configuration }
}
}
/// struct for passing parameters to the method [`TagNginxtagApi::validate`]
#[derive(Clone, Debug)]
pub struct ValidateParams {
pub validate_body: models::ValidateBody
}
/// struct for passing parameters to the method [`TagNginxtagApi::validate_and_reload`]
#[derive(Clone, Debug)]
pub struct ValidateAndReloadParams {
pub validate_and_reload_body: models::ValidateAndReloadBody
}
/// struct for passing parameters to the method [`TagNginxtagApi::write_config`]
#[derive(Clone, Debug)]
pub struct WriteConfigParams {
pub write_config_body: models::WriteConfigBody
}
#[async_trait]
impl TagNginxtagApi for TagNginxtagApiClient {
async fn status(&self, ) -> Result<ResponseContent<StatusSuccess>, Error<StatusError>> {
let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/status", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;
let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<StatusSuccess> = serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Ok(local_var_result)
} else {
let local_var_entity: Option<StatusError> = serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Err(Error::ResponseError(local_var_error))
}
}
async fn validate(&self, params: ValidateParams ) -> Result<ResponseContent<ValidateSuccess>, Error<ValidateError>> {
let ValidateParams {
validate_body,
} = params;
let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/validate", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
local_var_req_builder = local_var_req_builder.json(&validate_body);
let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;
let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<ValidateSuccess> = serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Ok(local_var_result)
} else {
let local_var_entity: Option<ValidateError> = serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Err(Error::ResponseError(local_var_error))
}
}
async fn validate_and_reload(&self, params: ValidateAndReloadParams ) -> Result<ResponseContent<ValidateAndReloadSuccess>, Error<ValidateAndReloadError>> {
let ValidateAndReloadParams {
validate_and_reload_body,
} = params;
let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/validate_and_reload", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
local_var_req_builder = local_var_req_builder.json(&validate_and_reload_body);
let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;
let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<ValidateAndReloadSuccess> = serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Ok(local_var_result)
} else {
let local_var_entity: Option<ValidateAndReloadError> = serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Err(Error::ResponseError(local_var_error))
}
}
async fn write_config(&self, params: WriteConfigParams ) -> Result<ResponseContent<WriteConfigSuccess>, Error<WriteConfigError>> {
let WriteConfigParams {
write_config_body,
} = params;
let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/write_config", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
local_var_req_builder = local_var_req_builder.json(&write_config_body);
let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;
let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<WriteConfigSuccess> = serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Ok(local_var_result)
} else {
let local_var_entity: Option<WriteConfigError> = serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Err(Error::ResponseError(local_var_error))
}
}
}
/// struct for typed successes of method [`TagNginxtagApi::status`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum StatusSuccess {
Status200(models::StatusResp),
UnknownValue(serde_json::Value),
}
/// struct for typed successes of method [`TagNginxtagApi::validate`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValidateSuccess {
Status200(serde_json::Value),
UnknownValue(serde_json::Value),
}
/// struct for typed successes of method [`TagNginxtagApi::validate_and_reload`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValidateAndReloadSuccess {
Status200(models::ValidateAndReloadResp),
UnknownValue(serde_json::Value),
}
/// struct for typed successes of method [`TagNginxtagApi::write_config`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WriteConfigSuccess {
Status200(),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`TagNginxtagApi::status`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum StatusError {
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`TagNginxtagApi::validate`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValidateError {
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`TagNginxtagApi::validate_and_reload`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValidateAndReloadError {
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`TagNginxtagApi::write_config`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WriteConfigError {
Status500(serde_json::Value),
UnknownValue(serde_json::Value),
}

View File

@@ -0,0 +1,10 @@
#![allow(unused_imports)]
#![allow(clippy::too_many_arguments)]
extern crate serde;
extern crate serde_json;
extern crate serde_repr;
extern crate url;
pub mod apis;
pub mod models;

View File

@@ -0,0 +1,10 @@
pub mod status_resp;
pub use self::status_resp::StatusResp;
pub mod validate_and_reload_body;
pub use self::validate_and_reload_body::ValidateAndReloadBody;
pub mod validate_and_reload_resp;
pub use self::validate_and_reload_resp::ValidateAndReloadResp;
pub mod validate_body;
pub use self::validate_body::ValidateBody;
pub mod write_config_body;
pub use self::write_config_body::WriteConfigBody;

View File

@@ -0,0 +1,24 @@
/*
* yanpm-agent
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
* Generated by: https://openapi-generator.tech
*/
use crate::models;
use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct StatusResp {
#[serde(rename = "ok")]
pub ok: bool,
}
impl StatusResp {
pub fn new(ok: bool) -> StatusResp {
StatusResp { ok }
}
}

View File

@@ -0,0 +1,29 @@
/*
* yanpm-agent
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
* Generated by: https://openapi-generator.tech
*/
use crate::models;
use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidateAndReloadBody {
#[serde(rename = "config_name")]
pub config_name: String,
#[serde(rename = "timestamp")]
pub timestamp: i64,
}
impl ValidateAndReloadBody {
pub fn new(config_name: String, timestamp: i64) -> ValidateAndReloadBody {
ValidateAndReloadBody {
config_name,
timestamp,
}
}
}

View File

@@ -0,0 +1,26 @@
/*
* yanpm-agent
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
* Generated by: https://openapi-generator.tech
*/
use crate::models;
use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidateAndReloadResp {
#[serde(rename = "rc")]
pub rc: i32,
#[serde(rename = "ro")]
pub ro: String,
}
impl ValidateAndReloadResp {
pub fn new(rc: i32, ro: String) -> ValidateAndReloadResp {
ValidateAndReloadResp { rc, ro }
}
}

View File

@@ -0,0 +1,29 @@
/*
* yanpm-agent
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
* Generated by: https://openapi-generator.tech
*/
use crate::models;
use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidateBody {
#[serde(rename = "config_name")]
pub config_name: String,
#[serde(rename = "timestamp")]
pub timestamp: i64,
}
impl ValidateBody {
pub fn new(config_name: String, timestamp: i64) -> ValidateBody {
ValidateBody {
config_name,
timestamp,
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* yanpm-agent
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.1.0
*
* Generated by: https://openapi-generator.tech
*/
use crate::models;
use serde::{Deserialize, Serialize};
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct WriteConfigBody {
#[serde(rename = "config_name")]
pub config_name: String,
#[serde(rename = "content")]
pub content: String,
#[serde(rename = "timestamp")]
pub timestamp: i64,
}
impl WriteConfigBody {
pub fn new(config_name: String, content: String, timestamp: i64) -> WriteConfigBody {
WriteConfigBody {
config_name,
content,
timestamp,
}
}
}