Compare commits

..

2 commits

Author SHA1 Message Date
866a655ca1
update 2024-05-14 14:44:33 -05:00
265c035bd4
work 2024-01-28 20:20:37 -06:00
14 changed files with 663 additions and 476 deletions

View file

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const path = @import("src/path.zig");
pub fn build(b: *std.Build) void { pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
@ -8,13 +9,27 @@ pub fn build(b: *std.Build) void {
[]const u8, []const u8,
"ssh", "ssh",
"path to ssh binary", "path to ssh binary",
) orelse "ssh"; ) orelse ssh: {
const p = path.expandPath(b.allocator, "ssh") catch {
break :ssh "ssh";
} orelse {
break :ssh "ssh";
};
break :ssh p;
};
const telnet_path = b.option( const telnet_path = b.option(
[]const u8, []const u8,
"telnet", "telnet",
"path to telnet binary", "path to telnet binary",
) orelse "telnet"; ) orelse telnet: {
const p = path.expandPath(b.allocator, "telnet") catch {
break :telnet "telnet";
} orelse {
break :telnet "telnet";
};
break :telnet p;
};
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{
.name = "hostapps", .name = "hostapps",
@ -39,6 +54,16 @@ pub fn build(b: *std.Build) void {
exe.root_module.addImport("anzi", anzi.module("anzi")); exe.root_module.addImport("anzi", anzi.module("anzi"));
const netboxz = b.dependency(
"netboxz",
.{
.target = target,
.optimize = optimize,
},
);
exe.root_module.addImport("netboxz", netboxz.module("netboxz"));
const logz = b.dependency( const logz = b.dependency(
"logz", "logz",
.{ .{
@ -49,15 +74,15 @@ pub fn build(b: *std.Build) void {
exe.root_module.addImport("logz", logz.module("logz")); exe.root_module.addImport("logz", logz.module("logz"));
const yazap = b.dependency( const @"zig-cli" = b.dependency(
"yazap", "zig-cli",
.{ .{
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}, },
); );
exe.root_module.addImport("yazap", yazap.module("yazap")); exe.root_module.addImport("zig-cli", @"zig-cli".module("zig-cli"));
b.installArtifact(exe); b.installArtifact(exe);

View file

@ -4,25 +4,26 @@
.minimum_zig_version = "0.12.0", .minimum_zig_version = "0.12.0",
.dependencies = .{ .dependencies = .{
.logz = .{ .logz = .{
.url = "https://github.com/karlseguin/log.zig/archive/a70984c80eb67c448480377849ba2adb6e51cf73.tar.gz", .url = "https://github.com/karlseguin/log.zig/archive/eb86766b91cf2ca0a6e87dd8568fab80695cf2e8.tar.gz",
.hash = "122090c83a4e52b454e006da4a804b2210136ddec0dccfae00e7097314e5acfd01d0", .hash = "1220b6cf56de826aead943a6db2a62ed40d81a150c24dcb019b3eb88673c82a6e7b7",
},
.yazap = .{
.url = "https://github.com/prajwalch/yazap/archive/5f0d5d8928d5cd1907760dc41fa6f05dd232aaa5.tar.gz",
.hash = "1220e4674826a70402974f13b7e2aaa4e9242e1b2b9d592015de9e21c7fa5fe200bd",
}, },
.anzi = .{ .anzi = .{
.url = "https://git.ocjtech.us/jeff/anzi/archive/0e9d395a55b16da1d5bf7bfb59e2cfa59a7f2630.tar.gz", .url = "https://git.ocjtech.us/jeff/anzi/archive/0e9d395a55b16da1d5bf7bfb59e2cfa59a7f2630.tar.gz",
.hash = "12203f0ed986047bcd860b00496979a7734c2f462da4e56a72add4b17a1a7981f8ec", .hash = "12203f0ed986047bcd860b00496979a7734c2f462da4e56a72add4b17a1a7981f8ec",
}, },
.netboxz = .{
// .url = "https://github.com/jcollie/netboxz/archive/354caea69a1e033cf34da6c5e514dc4eb755af06.tar.gz",
// .hash = "1220374f4587ec4d1e820a45039cd4bedd7cd560a3a668fdae2db0b5a6609f97c793",
.path = "../netboxz",
},
.@"zig-cli" = .{
.url = "https://github.com/sam701/zig-cli/archive/50201f0086da689cd104c2fef350f3dbe894eea7.tar.gz",
.hash = "12208a4377c7699927605e5a797bad5ae2ba8be4b49f68b9f522b3a755597a21f1cf",
},
}, },
.paths = .{ .paths = .{
// "",
// For example...
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src", "src",
// "LICENSE",
// "README.md",
}, },
} }

View file

@ -1,31 +1,15 @@
{ {
"nodes": { "nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1701680307, "lastModified": 1710146030,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725", "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -34,54 +18,6 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils_2": {
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"zls",
"nixpkgs"
]
},
"locked": {
"lastModified": 1703887061,
"narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"langref": {
"flake": false,
"locked": {
"narHash": "sha256-mYdDCBdNEIeMbavdhSo8qXqW+3fqPC8BAich7W3umrI=",
"type": "file",
"url": "https://raw.githubusercontent.com/ziglang/zig/63bd2bff12992aef0ce23ae4b344e9cb5d65f05d/doc/langref.html.in"
},
"original": {
"type": "file",
"url": "https://raw.githubusercontent.com/ziglang/zig/63bd2bff12992aef0ce23ae4b344e9cb5d65f05d/doc/langref.html.in"
}
},
"make-shell": { "make-shell": {
"locked": { "locked": {
"lastModified": 1634940815, "lastModified": 1634940815,
@ -105,11 +41,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1698974481, "lastModified": 1703863825,
"narHash": "sha256-yPncV9Ohdz1zPZxYHQf47S8S0VrnhV7nNhCawY46hDA=", "narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix-github-actions", "repo": "nix-github-actions",
"rev": "4bb5e752616262457bc7ca5882192a564c0472d2", "rev": "5163432afc817cf8bd1f031418d1869e4c9d5547",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -120,11 +56,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1704722960, "lastModified": 1715534503,
"narHash": "sha256-mKGJ3sPsT6//s+Knglai5YflJUF2DGj7Ai6Ynopz0kI=", "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "317484b1ead87b9c1b8ac5261a8d2dd748a0492d", "rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -147,11 +83,11 @@
"treefmt-nix": "treefmt-nix" "treefmt-nix": "treefmt-nix"
}, },
"locked": { "locked": {
"lastModified": 1705060653, "lastModified": 1715251496,
"narHash": "sha256-puYyylgrBS4AFAHeyVRTjTUVD8DZdecJfymWJe7H438=", "narHash": "sha256-vRBfJCKvJtu5sYev56XStirA3lAOPv0EkoEV2Nfc+tc=",
"owner": "nix-community", "owner": "nix-community",
"repo": "poetry2nix", "repo": "poetry2nix",
"rev": "e0b44e9e2d3aa855d1dd77b06f067cd0e0c3860d", "rev": "291a863e866972f356967d0a270b259f46bf987f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -165,9 +101,7 @@
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"make-shell": "make-shell", "make-shell": "make-shell",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"poetry2nix": "poetry2nix", "poetry2nix": "poetry2nix"
"zig": "zig",
"zls": "zls"
} }
}, },
"systems": { "systems": {
@ -207,11 +141,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1699786194, "lastModified": 1714058656,
"narHash": "sha256-3h3EH1FXQkIeAuzaWB+nK0XK54uSD46pp+dMD3gAcB4=", "narHash": "sha256-Qv4RBm4LKuO4fNOfx9wl40W2rBbv5u5m+whxRYUMiaA=",
"owner": "numtide", "owner": "numtide",
"repo": "treefmt-nix", "repo": "treefmt-nix",
"rev": "e82f32aa7f06bbbd56d7b12186d555223dc399d1", "rev": "c6aaf729f34a36c445618580a9f95a48f5e4e03f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -219,56 +153,6 @@
"repo": "treefmt-nix", "repo": "treefmt-nix",
"type": "github" "type": "github"
} }
},
"zig": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1705040559,
"narHash": "sha256-6SjLyxWAVMfVfkz2x/3IlAJBJ0ywus6Hr9JrBbT9zCk=",
"owner": "mitchellh",
"repo": "zig-overlay",
"rev": "6022b38d2fd4e7504f1e8b6dcfccab9b655764a9",
"type": "github"
},
"original": {
"owner": "mitchellh",
"repo": "zig-overlay",
"type": "github"
}
},
"zls": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"gitignore": "gitignore",
"langref": "langref",
"nixpkgs": [
"nixpkgs"
],
"zig-overlay": [
"zig"
]
},
"locked": {
"lastModified": 1705106613,
"narHash": "sha256-nqAXd8pEiEPJfjTrs0WB2UFOuBg5QRNbHWPDPGtrULI=",
"owner": "zigtools",
"repo": "zls",
"rev": "abe83cf2291381291d4c20629a5018f124c4bed2",
"type": "github"
},
"original": {
"owner": "zigtools",
"repo": "zls",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View file

@ -15,25 +15,23 @@
make-shell = { make-shell = {
url = "github:ursi/nix-make-shell"; url = "github:ursi/nix-make-shell";
}; };
zig = { # zig = {
url = "github:mitchellh/zig-overlay"; # url = "github:mitchellh/zig-overlay";
inputs.nixpkgs.follows = "nixpkgs"; # inputs.nixpkgs.follows = "nixpkgs";
}; # };
zls = { # zls = {
url = "github:zigtools/zls"; # url = "github:zigtools/zls";
inputs.nixpkgs.follows = "nixpkgs"; # inputs.nixpkgs.follows = "nixpkgs";
inputs.zig-overlay.follows = "zig"; # inputs.zig-overlay.follows = "zig";
inputs.flake-utils.follows = "flake-utils"; # inputs.flake-utils.follows = "flake-utils";
}; # };
}; };
outputs = { outputs = {
self, self,
nixpkgs, nixpkgs,
poetry2nix, poetry2nix,
flake-utils, flake-utils,
make-shell, ...
zig,
zls,
} @ inputs: } @ inputs:
flake-utils.lib.eachDefaultSystem flake-utils.lib.eachDefaultSystem
( (
@ -86,7 +84,7 @@
inherit src; inherit src;
name = "hostapps-zig-cache"; name = "hostapps-zig-cache";
buildInputs = [ buildInputs = [
zig.packages.${pkgs.system}.master pkgs.zig_0_12
]; ];
dontUseZigInstall = true; dontUseZigInstall = true;
dontUseZigBuild = true; dontUseZigBuild = true;
@ -120,7 +118,7 @@
src = ./.; src = ./.;
buildInputs = [ buildInputs = [
zig.packages.${pkgs.system}.master pkgs.zig_0_12
]; ];
preBuild = '' preBuild = ''
@ -161,8 +159,8 @@
pkgs.openssh pkgs.openssh
pkgs.poetry pkgs.poetry
pkgs.sshpass pkgs.sshpass
zig.packages.${system}.master pkgs.zig_0_12
zls.packages.${system}.zls pkgs.zls
]; ];
env = { env = {
name = project; name = project;

View file

@ -19,15 +19,21 @@ def main():
threading=True, threading=True,
) )
appdir = pathlib.Path("~/dev/home-manager/hostapps.json").expanduser().resolve() appdir = pathlib.Path("~/dev/nixos-desktops/hostapps.json").expanduser().resolve()
data = {} data = {}
cisco = nb.dcim.manufacturers.get(name="Cisco") cisco = nb.dcim.manufacturers.get(name="Cisco")
network = nb.dcim.device_roles.get(name="Network") if cisco is None:
return
role_ids = []
for name in ["Network", "Network Core", "Network Edge", "Network WAN"]:
role = nb.dcim.device_roles.get(name=name)
if role is not None:
role_ids.append(role.id)
for device in nb.dcim.devices.filter( for device in nb.dcim.devices.filter(
manufacturer_id=cisco.id, manufacturer_id=cisco.id,
role_id=network.id, role_id=role_ids,
status="active", status="active",
has_primary_ip="true", has_primary_ip="true",
): ):
@ -58,11 +64,17 @@ def main():
print(name, str(ipaddress.ip_interface(device.primary_ip4.address).ip)) print(name, str(ipaddress.ip_interface(device.primary_ip4.address).ip))
schneider = nb.dcim.manufacturers.get(name="Schneider") schneider = nb.dcim.manufacturers.get(name="Schneider")
power_protection = nb.dcim.device_roles.get(name="Power Protection") if schneider is None:
power_distribution = nb.dcim.device_roles.get(name="Power Distribution") return
role_ids = []
for name in ["Power Protection", "Power Distribution"]:
role = nb.dcim.device_roles.get(name=name)
if role is not None:
role_ids.append(role.id)
for device in nb.dcim.devices.filter( for device in nb.dcim.devices.filter(
manufacturer_id=schneider.id, manufacturer_id=schneider.id,
role_id=[power_protection.id, power_distribution.id], role_id=role_ids,
status="active", status="active",
has_primary_ip="true", has_primary_ip="true",
): ):

213
poetry.lock generated
View file

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. # This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
[[package]] [[package]]
name = "annotated-types" name = "annotated-types"
@ -317,18 +317,18 @@ files = [
[[package]] [[package]]
name = "pydantic" name = "pydantic"
version = "2.4.2" version = "2.7.1"
description = "Data validation using Python type hints" description = "Data validation using Python type hints"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "pydantic-2.4.2-py3-none-any.whl", hash = "sha256:bc3ddf669d234f4220e6e1c4d96b061abe0998185a8d7855c0126782b7abc8c1"}, {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"},
{file = "pydantic-2.4.2.tar.gz", hash = "sha256:94f336138093a5d7f426aac732dcfe7ab4eb4da243c88f891d65deb4a2556ee7"}, {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"},
] ]
[package.dependencies] [package.dependencies]
annotated-types = ">=0.4.0" annotated-types = ">=0.4.0"
pydantic-core = "2.10.1" pydantic-core = "2.18.2"
typing-extensions = ">=4.6.1" typing-extensions = ">=4.6.1"
[package.extras] [package.extras]
@ -336,117 +336,90 @@ email = ["email-validator (>=2.0.0)"]
[[package]] [[package]]
name = "pydantic-core" name = "pydantic-core"
version = "2.10.1" version = "2.18.2"
description = "" description = "Core functionality for Pydantic validation and serialization"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "pydantic_core-2.10.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:d64728ee14e667ba27c66314b7d880b8eeb050e58ffc5fec3b7a109f8cddbd63"}, {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"},
{file = "pydantic_core-2.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:48525933fea744a3e7464c19bfede85df4aba79ce90c60b94d8b6e1eddd67096"}, {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef337945bbd76cce390d1b2496ccf9f90b1c1242a3a7bc242ca4a9fc5993427a"}, {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1392e0638af203cee360495fd2cfdd6054711f2db5175b6e9c3c461b76f5175"}, {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0675ba5d22de54d07bccde38997e780044dcfa9a71aac9fd7d4d7a1d2e3e65f7"}, {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:128552af70a64660f21cb0eb4876cbdadf1a1f9d5de820fed6421fa8de07c893"}, {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f6e6aed5818c264412ac0598b581a002a9f050cb2637a84979859e70197aa9e"}, {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"},
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ecaac27da855b8d73f92123e5f03612b04c5632fd0a476e469dfc47cd37d6b2e"}, {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"},
{file = "pydantic_core-2.10.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3c01c2fb081fced3bbb3da78510693dc7121bb893a1f0f5f4b48013201f362e"}, {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"},
{file = "pydantic_core-2.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:92f675fefa977625105708492850bcbc1182bfc3e997f8eecb866d1927c98ae6"}, {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"},
{file = "pydantic_core-2.10.1-cp310-none-win32.whl", hash = "sha256:420a692b547736a8d8703c39ea935ab5d8f0d2573f8f123b0a294e49a73f214b"}, {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"},
{file = "pydantic_core-2.10.1-cp310-none-win_amd64.whl", hash = "sha256:0880e239827b4b5b3e2ce05e6b766a7414e5f5aedc4523be6b68cfbc7f61c5d0"}, {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"},
{file = "pydantic_core-2.10.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:073d4a470b195d2b2245d0343569aac7e979d3a0dcce6c7d2af6d8a920ad0bea"}, {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"},
{file = "pydantic_core-2.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:600d04a7b342363058b9190d4e929a8e2e715c5682a70cc37d5ded1e0dd370b4"}, {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39215d809470f4c8d1881758575b2abfb80174a9e8daf8f33b1d4379357e417c"}, {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eeb3d3d6b399ffe55f9a04e09e635554012f1980696d6b0aca3e6cf42a17a03b"}, {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a7902bf75779bc12ccfc508bfb7a4c47063f748ea3de87135d433a4cca7a2f"}, {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3625578b6010c65964d177626fde80cf60d7f2e297d56b925cb5cdeda6e9925a"}, {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:caa48fc31fc7243e50188197b5f0c4228956f97b954f76da157aae7f67269ae8"}, {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"},
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:07ec6d7d929ae9c68f716195ce15e745b3e8fa122fc67698ac6498d802ed0fa4"}, {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"},
{file = "pydantic_core-2.10.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6f31a17acede6a8cd1ae2d123ce04d8cca74056c9d456075f4f6f85de055607"}, {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"},
{file = "pydantic_core-2.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d8f1ebca515a03e5654f88411420fea6380fc841d1bea08effb28184e3d4899f"}, {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"},
{file = "pydantic_core-2.10.1-cp311-none-win32.whl", hash = "sha256:6db2eb9654a85ada248afa5a6db5ff1cf0f7b16043a6b070adc4a5be68c716d6"}, {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"},
{file = "pydantic_core-2.10.1-cp311-none-win_amd64.whl", hash = "sha256:4a5be350f922430997f240d25f8219f93b0c81e15f7b30b868b2fddfc2d05f27"}, {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"},
{file = "pydantic_core-2.10.1-cp311-none-win_arm64.whl", hash = "sha256:5fdb39f67c779b183b0c853cd6b45f7db84b84e0571b3ef1c89cdb1dfc367325"}, {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"},
{file = "pydantic_core-2.10.1-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1f22a9ab44de5f082216270552aa54259db20189e68fc12484873d926426921"}, {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"},
{file = "pydantic_core-2.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8572cadbf4cfa95fb4187775b5ade2eaa93511f07947b38f4cd67cf10783b118"}, {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db9a28c063c7c00844ae42a80203eb6d2d6bbb97070cfa00194dff40e6f545ab"}, {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e2a35baa428181cb2270a15864ec6286822d3576f2ed0f4cd7f0c1708472aff"}, {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05560ab976012bf40f25d5225a58bfa649bb897b87192a36c6fef1ab132540d7"}, {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6495008733c7521a89422d7a68efa0a0122c99a5861f06020ef5b1f51f9ba7c"}, {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ac492c686defc8e6133e3a2d9eaf5261b3df26b8ae97450c1647286750b901"}, {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"},
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8282bab177a9a3081fd3d0a0175a07a1e2bfb7fcbbd949519ea0980f8a07144d"}, {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"},
{file = "pydantic_core-2.10.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:aafdb89fdeb5fe165043896817eccd6434aee124d5ee9b354f92cd574ba5e78f"}, {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"},
{file = "pydantic_core-2.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f6defd966ca3b187ec6c366604e9296f585021d922e666b99c47e78738b5666c"}, {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"},
{file = "pydantic_core-2.10.1-cp312-none-win32.whl", hash = "sha256:7c4d1894fe112b0864c1fa75dffa045720a194b227bed12f4be7f6045b25209f"}, {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"},
{file = "pydantic_core-2.10.1-cp312-none-win_amd64.whl", hash = "sha256:5994985da903d0b8a08e4935c46ed8daf5be1cf217489e673910951dc533d430"}, {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"},
{file = "pydantic_core-2.10.1-cp312-none-win_arm64.whl", hash = "sha256:0d8a8adef23d86d8eceed3e32e9cca8879c7481c183f84ed1a8edc7df073af94"}, {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"},
{file = "pydantic_core-2.10.1-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9badf8d45171d92387410b04639d73811b785b5161ecadabf056ea14d62d4ede"}, {file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"},
{file = "pydantic_core-2.10.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:ebedb45b9feb7258fac0a268a3f6bec0a2ea4d9558f3d6f813f02ff3a6dc6698"}, {file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfe1090245c078720d250d19cb05d67e21a9cd7c257698ef139bc41cf6c27b4f"}, {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e357571bb0efd65fd55f18db0a2fb0ed89d0bb1d41d906b138f088933ae618bb"}, {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3dcd587b69bbf54fc04ca157c2323b8911033e827fffaecf0cafa5a892a0904"}, {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c120c9ce3b163b985a3b966bb701114beb1da4b0468b9b236fc754783d85aa3"}, {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15d6bca84ffc966cc9976b09a18cf9543ed4d4ecbd97e7086f9ce9327ea48891"}, {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"},
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cabb9710f09d5d2e9e2748c3e3e20d991a4c5f96ed8f1132518f54ab2967221"}, {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"},
{file = "pydantic_core-2.10.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:82f55187a5bebae7d81d35b1e9aaea5e169d44819789837cdd4720d768c55d15"}, {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"},
{file = "pydantic_core-2.10.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1d40f55222b233e98e3921df7811c27567f0e1a4411b93d4c5c0f4ce131bc42f"}, {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"},
{file = "pydantic_core-2.10.1-cp37-none-win32.whl", hash = "sha256:14e09ff0b8fe6e46b93d36a878f6e4a3a98ba5303c76bb8e716f4878a3bee92c"}, {file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"},
{file = "pydantic_core-2.10.1-cp37-none-win_amd64.whl", hash = "sha256:1396e81b83516b9d5c9e26a924fa69164156c148c717131f54f586485ac3c15e"}, {file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"},
{file = "pydantic_core-2.10.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6835451b57c1b467b95ffb03a38bb75b52fb4dc2762bb1d9dbed8de31ea7d0fc"}, {file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"},
{file = "pydantic_core-2.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b00bc4619f60c853556b35f83731bd817f989cba3e97dc792bb8c97941b8053a"}, {file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fa467fd300a6f046bdb248d40cd015b21b7576c168a6bb20aa22e595c8ffcdd"}, {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d99277877daf2efe074eae6338453a4ed54a2d93fb4678ddfe1209a0c93a2468"}, {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa7db7558607afeccb33c0e4bf1c9a9a835e26599e76af6fe2fcea45904083a6"}, {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aad7bd686363d1ce4ee930ad39f14e1673248373f4a9d74d2b9554f06199fb58"}, {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:443fed67d33aa85357464f297e3d26e570267d1af6fef1c21ca50921d2976302"}, {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"},
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:042462d8d6ba707fd3ce9649e7bf268633a41018d6a998fb5fbacb7e928a183e"}, {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"},
{file = "pydantic_core-2.10.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ecdbde46235f3d560b18be0cb706c8e8ad1b965e5c13bbba7450c86064e96561"}, {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"},
{file = "pydantic_core-2.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ed550ed05540c03f0e69e6d74ad58d026de61b9eaebebbaaf8873e585cbb18de"}, {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"},
{file = "pydantic_core-2.10.1-cp38-none-win32.whl", hash = "sha256:8cdbbd92154db2fec4ec973d45c565e767ddc20aa6dbaf50142676484cbff8ee"}, {file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"},
{file = "pydantic_core-2.10.1-cp38-none-win_amd64.whl", hash = "sha256:9f6f3e2598604956480f6c8aa24a3384dbf6509fe995d97f6ca6103bb8c2534e"}, {file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"},
{file = "pydantic_core-2.10.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:655f8f4c8d6a5963c9a0687793da37b9b681d9ad06f29438a3b2326d4e6b7970"}, {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"},
{file = "pydantic_core-2.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e570ffeb2170e116a5b17e83f19911020ac79d19c96f320cbfa1fa96b470185b"}, {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64322bfa13e44c6c30c518729ef08fda6026b96d5c0be724b3c4ae4da939f875"}, {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:485a91abe3a07c3a8d1e082ba29254eea3e2bb13cbbd4351ea4e5a21912cc9b0"}, {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7c2b8eb9fc872e68b46eeaf835e86bccc3a58ba57d0eedc109cbb14177be531"}, {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5cb87bdc2e5f620693148b5f8f842d293cae46c5f15a1b1bf7ceeed324a740c"}, {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25bd966103890ccfa028841a8f30cebcf5875eeac8c4bde4fe221364c92f0c9a"}, {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"},
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f323306d0556351735b54acbf82904fe30a27b6a7147153cbe6e19aaaa2aa429"}, {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"},
{file = "pydantic_core-2.10.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0c27f38dc4fbf07b358b2bc90edf35e82d1703e22ff2efa4af4ad5de1b3833e7"}, {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"},
{file = "pydantic_core-2.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f1365e032a477c1430cfe0cf2856679529a2331426f8081172c4a74186f1d595"}, {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"},
{file = "pydantic_core-2.10.1-cp39-none-win32.whl", hash = "sha256:a1c311fd06ab3b10805abb72109f01a134019739bd3286b8ae1bc2fc4e50c07a"}, {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"},
{file = "pydantic_core-2.10.1-cp39-none-win_amd64.whl", hash = "sha256:ae8a8843b11dc0b03b57b52793e391f0122e740de3df1474814c700d2622950a"}, {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d43002441932f9a9ea5d6f9efaa2e21458221a3a4b417a14027a1d530201ef1b"}, {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fcb83175cc4936a5425dde3356f079ae03c0802bbdf8ff82c035f8a54b333521"}, {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:962ed72424bf1f72334e2f1e61b68f16c0e596f024ca7ac5daf229f7c26e4208"}, {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cf5bb4dd67f20f3bbc1209ef572a259027c49e5ff694fa56bed62959b41e1f9"}, {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e544246b859f17373bed915182ab841b80849ed9cf23f1f07b73b7c58baee5fb"}, {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c0877239307b7e69d025b73774e88e86ce82f6ba6adf98f41069d5b0b78bd1bf"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:53df009d1e1ba40f696f8995683e067e3967101d4bb4ea6f667931b7d4a01357"},
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a1254357f7e4c82e77c348dabf2d55f1d14d19d91ff025004775e70a6ef40ada"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:524ff0ca3baea164d6d93a32c58ac79eca9f6cf713586fdc0adb66a8cdeab96a"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f0ac9fb8608dbc6eaf17956bf623c9119b4db7dbb511650910a82e261e6600f"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:320f14bd4542a04ab23747ff2c8a778bde727158b606e2661349557f0770711e"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:63974d168b6233b4ed6a0046296803cb13c56637a7b8106564ab575926572a55"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:417243bf599ba1f1fef2bb8c543ceb918676954734e2dcb82bf162ae9d7bd514"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dda81e5ec82485155a19d9624cfcca9be88a405e2857354e5b089c2a982144b2"},
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:14cfbb00959259e15d684505263d5a21732b31248a5dd4941f73a3be233865b9"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:631cb7415225954fdcc2a024119101946793e5923f6c4d73a5914d27eb3d3a05"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:bec7dd208a4182e99c5b6c501ce0b1f49de2802448d4056091f8e630b28e9a52"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:149b8a07712f45b332faee1a2258d8ef1fb4a36f88c0c17cb687f205c5dc6e7d"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d966c47f9dd73c2d32a809d2be529112d509321c5310ebf54076812e6ecd884"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7eb037106f5c6b3b0b864ad226b0b7ab58157124161d48e4b30c4a43fef8bc4b"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:154ea7c52e32dce13065dbb20a4a6f0cc012b4f667ac90d648d36b12007fa9f7"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e562617a45b5a9da5be4abe72b971d4f00bf8555eb29bb91ec2ef2be348cd132"},
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f23b55eb5464468f9e0e9a9935ce3ed2a870608d5f534025cd5536bca25b1402"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:e9121b4009339b0f751955baf4543a0bfd6bc3f8188f8056b1a25a2d45099934"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0523aeb76e03f753b58be33b26540880bac5aa54422e4462404c432230543f33"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e0e2959ef5d5b8dc9ef21e1a305a21a36e254e6a34432d00c72a92fdc5ecda5"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da01bec0a26befab4898ed83b362993c844b9a607a86add78604186297eb047e"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f2e9072d71c1f6cfc79a36d4484c82823c560e6f5599c43c1ca6b5cdbd54f881"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f36a3489d9e28fe4b67be9992a23029c3cec0babc3bd9afb39f49844a8c721c5"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f64f82cc3443149292b32387086d02a6c7fb39b8781563e0ca7b8d7d9cf72bd7"},
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b4a6db486ac8e99ae696e09efc8b2b9fea67b63c8f88ba7a1a16c24a057a0776"},
{file = "pydantic_core-2.10.1.tar.gz", hash = "sha256:0f8682dbdd2f67f8e1edddcbffcc29f60a6182b4901c367fc8c1c40d30bb0a82"},
] ]
[package.dependencies] [package.dependencies]
@ -465,13 +438,13 @@ files = [
[[package]] [[package]]
name = "pynetbox" name = "pynetbox"
version = "7.2.0" version = "7.3.3"
description = "NetBox API client library" description = "NetBox API client library"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
{file = "pynetbox-7.2.0-py3-none-any.whl", hash = "sha256:73ac66250f8899152180b5e1fca63402d4aef8ed361b291f19d7ba3730f87a6c"}, {file = "pynetbox-7.3.3-py3-none-any.whl", hash = "sha256:9bc25f83ff126f12d26976e544a2f0f6c7c898c261e6d47f8a4144ab47686d81"},
{file = "pynetbox-7.2.0.tar.gz", hash = "sha256:3735f4d44e81da4b9af3cc1fdf18e708752ac5d863442100d987886c099df5df"}, {file = "pynetbox-7.3.3.tar.gz", hash = "sha256:b0bcef4c3a019516d2425ae0ce5509eae7f4f11ad4510c9fe9527d468f22529b"},
] ]
[package.dependencies] [package.dependencies]
@ -529,5 +502,5 @@ zstd = ["zstandard (>=0.18.0)"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.12"
content-hash = "0f00fce7b8e9105d105a1f4eb94ed491a60930d94b988175ab3843df6e900fff" content-hash = "0e934e61e0a98143a9f43eda7b0d2cc3ad86ee12a35d7d4b9ce57f5b369b80aa"

View file

@ -5,10 +5,10 @@ description = ""
authors = ["Jeffrey C. Ollie <jeff@ocjtech.us>"] authors = ["Jeffrey C. Ollie <jeff@ocjtech.us>"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.11" python = "^3.12"
pynetbox = "^7.2.0" pynetbox = "^7.3.3"
click = "^8.1.7" click = "^8.1.7"
pydantic = "^2.4.2" pydantic = "^2.7.1"
pyansi = { git = "https://git.ocjtech.us/jeff/pyansi" } pyansi = { git = "https://git.ocjtech.us/jeff/pyansi" }
#pyansi = { path = "/home/jeff/dev/pyansi", develop = true } #pyansi = { path = "/home/jeff/dev/pyansi", develop = true }
requests = "^2.31.0" requests = "^2.31.0"

View file

@ -9,7 +9,7 @@ pub const Config = struct {
name: []const u8, name: []const u8,
type: ConnectionType, type: ConnectionType,
comment: []const u8, comment: []const u8,
address: []const u8, addresses: [][]const u8,
port: u16, port: u16,
username: []const u8, username: []const u8,
manufacturer: []const u8, manufacturer: []const u8,
@ -22,7 +22,28 @@ pub const Config = struct {
pub fn read(alloc: std.mem.Allocator, path: []const u8) !Self { pub fn read(alloc: std.mem.Allocator, path: []const u8) !Self {
const data = try std.fs.cwd().readFileAlloc(alloc, path, 2048); const data = try std.fs.cwd().readFileAlloc(alloc, path, 2048);
const parsed = try std.json.parseFromSlice(Self, alloc, data, .{}); const parsed = try std.json.parseFromSlice(Self, alloc, data, .{});
const config = parsed.value; defer parsed.deinit();
return config; return try parsed.value.clone(alloc);
}
pub fn clone(self: Self, alloc: std.mem.Allocator) !Self {
return .{
.name = try alloc.dupe(u8, self.name),
.type = self.type,
.comment = try alloc.dupe(u8, self.comment),
.addresses = addr: {
var addrs = try alloc.alloc([]const u8, self.addresses.len);
for (self.addresses, 0..) |a, i| {
addrs[i] = try alloc.dupe(u8, a);
}
break :addr addrs;
},
.port = self.port,
.username = try alloc.dupe(u8, self.username),
.manufacturer = try alloc.dupe(u8, self.manufacturer),
.model = try alloc.dupe(u8, self.model),
.part_number = try alloc.dupe(u8, self.part_number),
.class = try alloc.dupe(u8, self.class),
};
} }
}; };

View file

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const Config = @import("config.zig").Config; const Config = @import("config.zig").Config;
const options = @import("options.zig");
const ansi = @import("anzi").ANSI(.{}); const ansi = @import("anzi").ANSI(.{});
const kex_algorithms = [_][]const u8{ const kex_algorithms = [_][]const u8{
@ -30,7 +31,7 @@ const macs = [_][]const u8{
"hmac-sha2-512", "hmac-sha2-512",
}; };
const options = [_]struct { key: []const u8, value: []const u8 }{ const ssh_options = [_]struct { key: []const u8, value: []const u8 }{
.{ .key = "ControlMaster", .value = "no" }, .{ .key = "ControlMaster", .value = "no" },
.{ .key = "ControlPath", .value = "none" }, .{ .key = "ControlPath", .value = "none" },
.{ .key = "ForwardX11", .value = "no" }, .{ .key = "ForwardX11", .value = "no" },
@ -39,19 +40,14 @@ const options = [_]struct { key: []const u8, value: []const u8 }{
.{ .key = "PubkeyAcceptedKeyTypes", .value = "+ssh-rsa" }, .{ .key = "PubkeyAcceptedKeyTypes", .value = "+ssh-rsa" },
}; };
pub fn connect( pub fn connect() !void {
allocator: std.mem.Allocator, var arena = std.heap.ArenaAllocator.init(options.options.alloc);
config_path: []const u8,
identities: ?[][]const u8,
proxy_jump: ?[]const u8,
ssh_path: []const u8,
telnet_path: []const u8,
) !void {
var arena = std.heap.ArenaAllocator.init(allocator);
const alloc = arena.allocator(); const alloc = arena.allocator();
defer arena.deinit(); defer arena.deinit();
const config = try Config.read(alloc, config_path); std.log.info("config: {}", .{options.options});
const config = try Config.read(options.options.alloc, options.options.config);
var path: []const u8 = undefined; var path: []const u8 = undefined;
var args = std.ArrayList([]const u8).init(alloc); var args = std.ArrayList([]const u8).init(alloc);
@ -69,23 +65,21 @@ pub fn connect(
switch (config.type) { switch (config.type) {
.ssh => { .ssh => {
path = ssh_path; path = options.options.ssh_path;
try args.append("ssh"); try args.append("ssh");
try args.append("-y"); try args.append("-y");
if (identities) |i| { for (options.options.identities) |identity| {
for (i) |identity| {
try args.append("-i"); try args.append("-i");
try args.append(identity); try args.append(identity);
} }
}
if (proxy_jump) |p| { if (options.options.proxy_jump) |p| {
try args.append("-o"); try args.append("-o");
try args.append(try std.fmt.allocPrint(alloc, "ProxyJump={s}", .{p})); try args.append(try std.fmt.allocPrint(alloc, "ProxyJump={s}", .{p}));
} }
for (options) |option| { for (ssh_options) |option| {
try args.append("-o"); try args.append("-o");
try args.append(try std.fmt.allocPrint(alloc, "{s}={s}", .{ option.key, option.value })); try args.append(try std.fmt.allocPrint(alloc, "{s}={s}", .{ option.key, option.value }));
} }
@ -111,14 +105,14 @@ pub fn connect(
}, },
.telnet => { .telnet => {
if (proxy_jump) |p| { if (options.options.proxy_jump) |p| {
path = ssh_path; path = options.options.ssh_path;
try args.append("ssh"); try args.append("ssh");
try args.append("-t"); try args.append("-t");
try args.append(try std.fmt.allocPrint(alloc, "ssh://{s}", .{p})); try args.append(try std.fmt.allocPrint(alloc, "ssh://{s}", .{p}));
try args.append("telnet"); try args.append("telnet");
} else { } else {
path = telnet_path; path = options.options.telnet_path;
try args.append("telnet"); try args.append("telnet");
} }

37
src/hashmap.zig Normal file
View file

@ -0,0 +1,37 @@
const std = @import("std");
const Context = struct {
pub fn hash(_: @This(), key: u64) u64 {
return key;
}
pub fn eq(_: @This(), a: u64, b: u64) bool {
return a == b;
}
};
pub const HashMap = struct {
arena: std.heap.ArenaAllocator,
map: std.HashMap(u64, []const u8, Context, 75),
pub fn init(allocator: std.mem.Allocator) @This() {
var arena = std.heap.ArenaAllocator.init(allocator);
return .{
.arena = arena,
.map = std.HashMap(u64, []const u8, Context, 75).init(arena.allocator()),
};
}
pub fn deinit(self: @This()) void {
self.map.deinit();
self.arena.deinit();
}
pub fn put(self: @This(), k: u64, v: []const u8) !void {
try self.map.put(k, try self.arena.allocator().dupe(u8, v));
}
pub fn get(self: @This(), k: u64) ?[]const u8 {
return self.map.get(k);
}
};

View file

@ -1,169 +1,15 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const build_options = @import("build_options"); const build_options = @import("build_options");
const yazap = @import("yazap"); const cli = @import("zig-cli");
const logz = @import("logz");
const Config = @import("config.zig").Config;
const connect = @import("connect.zig"); const connect = @import("connect.zig");
const options = @import("options.zig");
const App = yazap.App;
const Arg = yazap.Arg;
pub fn main() !void { pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const alloc = gpa.allocator(); const alloc = gpa.allocator();
try logz.setup(alloc, .{ options.options.alloc = alloc;
.level = .Debug,
.pool_size = 16,
.max_size = 4096,
.output = .stderr,
});
var app = App.init(alloc, "hostapps", "hostapps"); return cli.run(options.app, alloc);
defer app.deinit();
var root = app.rootCommand();
try root.addArg(Arg.booleanOption("version", null, "Print version and exit"));
var connect_command = app.createCommand("connect", "connect to remote host");
try connect_command.addArg(Arg.singleValueOption("config", null, "Path to configuration file"));
try connect_command.addArg(Arg.multiValuesOption("identity", null, "Path to identity file", 8));
try connect_command.addArg(Arg.singleValueOption("proxy-jump", null, "Proxy jump"));
try connect_command.addArg(Arg.singleValueOption("ssh-command", null, "Path to ssh command"));
try connect_command.addArg(Arg.singleValueOption("telnet-command", null, "Path to telnet command"));
try root.addSubcommand(connect_command);
const matches = try app.parseProcess();
if (!(matches.containsArgs())) {
try app.displayHelp();
return;
}
if (matches.containsArg("version")) {
std.log.info("version number", .{});
return;
}
if (matches.subcommandMatches("connect")) |connect_matches| {
const config_path = connect_matches.getSingleValue("config") orelse {
try app.displaySubcommandHelp();
return;
};
const identities = id: {
const ids = connect_matches.getMultiValues("identity");
if (ids != null) break :id ids;
const id = connect_matches.getSingleValue("identity");
if (id) |i| {
break :id @as(?[][]const u8, @constCast(&[_][]const u8{i}));
}
break :id null;
};
if (identities) |i| {
for (i) |identity| {
logz.info().string("identity", identity).log();
const fullpath = fp: {
if (identity[0] == '~') {
const home = std.os.getenv("HOME") orelse {
logz.err().src(@src()).string("message", "unable to get HOME environment variable to expand tilde").log();
return;
};
var fp = try alloc.alloc(u8, home.len + identity.len - 1);
@memcpy(fp[0..home.len], home);
@memcpy(fp[home.len..], identity[1..]);
break :fp fp;
}
break :fp identity;
};
logz.info().string("fullpath", fullpath).log();
std.fs.cwd().access(fullpath, .{ .mode = .read_only }) catch |err| {
logz.err().src(@src()).err(err).string("identity", identity).string("fullpath", fullpath).log();
return;
};
if (identity.ptr != fullpath.ptr) alloc.free(fullpath);
}
}
const proxy_jump = connect_matches.getSingleValue("proxy-jump");
var ssh_path = connect_matches.getSingleValue("ssh-command") orelse build_options.ssh_path;
if (!std.fs.path.isAbsolute(ssh_path)) {
const expanded = expandPath(alloc, ssh_path) catch |err| expanded: {
std.log.warn("failed to expand ssh path={s} err={}", .{ ssh_path, err });
break :expanded null;
};
if (expanded) |v| {
ssh_path = v;
}
}
var telnet_path = connect_matches.getSingleValue("telnet-command") orelse build_options.telnet_path;
if (!std.fs.path.isAbsolute(telnet_path)) {
const expanded = expandPath(alloc, telnet_path) catch |err| expanded: {
std.log.warn("failed to expand telnet path={s} err={}", .{ telnet_path, err });
break :expanded null;
};
if (expanded) |v| {
telnet_path = v;
}
}
try connect.connect(alloc, config_path, identities, proxy_jump, ssh_path, telnet_path);
return;
}
}
fn expandPath(alloc: std.mem.Allocator, cmd: []const u8) !?[]u8 {
const PATH = switch (builtin.os.tag) {
.windows => blk: {
const win_path = std.os.getenvW(std.unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse return null;
const path = try std.unicode.utf16leToUtf8Alloc(alloc, win_path);
break :blk path;
},
else => std.os.getenvZ("PATH") orelse return null,
};
defer if (builtin.os.tag == .windows) alloc.free(PATH);
var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
var it = std.mem.tokenizeScalar(u8, PATH, std.fs.path.delimiter);
var seen_eaccess = false;
while (it.next()) |search_path| {
const path_len = search_path.len + cmd.len + 1;
if (path_buf.len < path_len) return error.PathTooLong;
@memcpy(path_buf[0..search_path.len], search_path);
path_buf[search_path.len] = std.fs.path.sep;
@memcpy(path_buf[search_path.len + 1 ..][0..cmd.len], cmd);
path_buf[path_len] = 0;
const full_path = path_buf[0..path_len :0];
const stat = std.fs.cwd().statFile(full_path) catch |err| switch (err) {
error.FileNotFound => continue,
error.AccessDenied => {
seen_eaccess = true;
continue;
},
else => return err,
};
if (stat.kind != .directory and isExecutable(stat.mode)) {
std.log.debug("executable: {s}", .{full_path});
return try alloc.dupe(u8, full_path);
}
}
if (seen_eaccess) return error.AccessDenied;
return null;
}
fn isExecutable(mode: std.fs.File.Mode) bool {
if (builtin.os.tag == .windows) return true;
return mode & 0o0111 != 0;
} }

99
src/options.zig Normal file
View file

@ -0,0 +1,99 @@
const std = @import("std");
const cli = @import("zig-cli");
const build_options = @import("build_options");
const connect = @import("connect.zig");
const update = @import("update.zig");
pub const Options = struct {
alloc: std.mem.Allocator = undefined,
config: []const u8 = undefined,
identities: []const []const u8 = undefined,
proxy_jump: ?[]const u8 = null,
ssh_path: []const u8,
telnet_path: []const u8,
};
pub var options: Options = .{
.ssh_path = build_options.ssh_path,
.telnet_path = build_options.telnet_path,
};
var config_option = cli.Option{
.long_name = "config",
.help = "config file",
.value_ref = cli.mkRef(&options.config),
.required = true,
};
var identity_option = cli.Option{
.long_name = "identity",
.help = "ssh identity",
.value_ref = cli.mkRef(&options.identities),
};
var proxy_jump_option = cli.Option{
.long_name = "proxy-jump",
.help = "proxy jump",
.value_ref = cli.mkRef(&options.proxy_jump),
};
var ssh_command_option = cli.Option{
.long_name = "ssh-command",
.help = "ssh command",
.value_ref = cli.mkRef(&options.ssh_path),
};
var telnet_command_option = cli.Option{
.long_name = "telnet-command",
.help = "telnet command",
.value_ref = cli.mkRef(&options.telnet_path),
};
var connect_command = cli.Command{
.name = "connect",
.description = cli.Description{
.one_line = "connect",
},
.options = &.{
&config_option,
&identity_option,
&proxy_jump_option,
&ssh_command_option,
&telnet_command_option,
},
.target = cli.CommandTarget{
.action = cli.CommandAction{
.exec = connect.connect,
},
},
};
var update_command = cli.Command{
.name = "update",
.description = cli.Description{
.one_line = "update",
},
.options = &.{},
.target = cli.CommandTarget{
.action = cli.CommandAction{
.exec = update.update,
},
},
};
pub const app = &cli.App{
.command = cli.Command{
.name = "hostapps",
.description = cli.Description{
.one_line = "hostapps",
},
.target = cli.CommandTarget{
.subcommands = &.{
&connect_command,
&update_command,
},
},
},
.version = "0.1.0",
.author = "Jeffrey C. Ollie <jcollie@dmacc.edu>",
};

49
src/path.zig Normal file
View file

@ -0,0 +1,49 @@
const std = @import("std");
const builtin = @import("builtin");
pub fn expandPath(alloc: std.mem.Allocator, cmd: []const u8) !?[]u8 {
const PATH = switch (builtin.os.tag) {
.windows => blk: {
const win_path = std.os.getenvW(std.unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse return null;
const path = try std.unicode.utf16leToUtf8Alloc(alloc, win_path);
break :blk path;
},
else => std.os.getenvZ("PATH") orelse return null,
};
defer if (builtin.os.tag == .windows) alloc.free(PATH);
var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
var it = std.mem.tokenizeScalar(u8, PATH, std.fs.path.delimiter);
var seen_eaccess = false;
while (it.next()) |search_path| {
const path_len = search_path.len + cmd.len + 1;
if (path_buf.len < path_len) return error.PathTooLong;
@memcpy(path_buf[0..search_path.len], search_path);
path_buf[search_path.len] = std.fs.path.sep;
@memcpy(path_buf[search_path.len + 1 ..][0..cmd.len], cmd);
path_buf[path_len] = 0;
const full_path = path_buf[0..path_len :0];
const stat = std.fs.cwd().statFile(full_path) catch |err| switch (err) {
error.FileNotFound => continue,
error.AccessDenied => {
seen_eaccess = true;
continue;
},
else => return err,
};
if (stat.kind != .directory and isExecutable(stat.mode)) {
return try alloc.dupe(u8, full_path);
}
}
if (seen_eaccess) return error.AccessDenied;
return null;
}
pub fn isExecutable(mode: std.fs.File.Mode) bool {
if (builtin.os.tag == .windows) return true;
return mode & 0o0111 != 0;
}

248
src/update.zig Normal file
View file

@ -0,0 +1,248 @@
const std = @import("std");
const builtin = @import("builtin");
const Config = @import("config.zig").Config;
const ConnectionType = @import("config.zig").ConnectionType;
const options = @import("options.zig");
const ansi = @import("anzi").ANSI(.{});
const netboxz = @import("netboxz");
const HashMap = @import("hashmap");
const log = std.log.scoped(.update);
pub fn update() !void {
var arena = std.heap.ArenaAllocator.init(options.options.alloc);
const alloc = arena.allocator();
defer arena.deinit();
const nb = try netboxz.init(alloc, "https://netbox.dmacc.net", "814e66254d019e7ef37de53bacc8e88e411da855");
const mfg_cisco_id = id: {
var one = try nb.dcim().manufacturers().one(
&[_]netboxz.FilterOperation{
.{
.string = .{
.key = "name",
.value = "Cisco",
.comparison = .eq,
},
},
},
);
defer one.deinit();
log.info("one: {any}", .{one.ok.value.name});
switch (one) {
.ok => |r| {
log.info("found manufacturer {d} {s}", .{ r.value.id, r.value.name });
break :id r.value.id;
},
.notfound => {
log.err("could not find Cisco", .{});
return;
},
.toomany => |r| {
log.err("{} is too many", .{r.count});
return;
},
.err => |r| {
log.err("error from netbox: {s}", .{r.detail});
return;
},
}
};
log.info("found mfg id {}", .{mfg_cisco_id});
const network_role_id = id: {
var one = try nb.dcim().device_roles().one(
&[_]netboxz.FilterOperation{
.{
.string = .{
.key = "name",
.value = "Network",
.comparison = .eq,
},
},
},
);
defer one.deinit();
switch (one) {
.ok => |r| {
break :id r.value.id;
},
.notfound => {
log.err("could not find Network", .{});
return;
},
.toomany => |r| {
log.err("{} is too many", .{r.count});
return;
},
.err => |r| {
log.err("error from netbox: {s}", .{r.detail});
return;
},
}
};
log.info("found role id {}", .{network_role_id});
{
var iter = try nb.dcim().devices().list(
.{
.filters = &[_]netboxz.FilterOperation{
.{
.fk = .{
.key = "manufacturer_id",
.value = mfg_cisco_id,
},
},
.{
.fk = .{
.key = "role_id",
.value = network_role_id,
},
},
.{
.choice = .{
.key = "status",
.value = "active",
},
},
.{
.boolean = .{
.key = "has_primary_ip",
.value = true,
},
},
},
},
);
var part_number_map = HashMap.init(alloc);
while (try iter.next()) |device_result| {
defer device_result.deinit();
switch (device_result) {
.ok => |devices| {
for (devices.items) |device| {
const name = name: {
if (device.virtual_chassis) |vc| break :name vc.name;
if (device.name) |name| break :name name;
break :name device.display;
};
log.info("found device {d} '{s}' '{s}'", .{ device.id, name, device.display });
const part_number = pn: {
if (part_number_map.get(device.device_type.id)) |pn| break :pn pn;
const pn_result = try device.device_type.full(nb);
switch (pn_result) {
.ok => |r| {
part_number_map.put(r.item.id, r.item.part_number);
break :pn r.item.part_number;
},
.err => |r| {
log.err("error: {}", .{r.detail});
return;
},
}
};
var service_iter = try nb.ipam().services().list(
.{
.filters = &[_]netboxz.FilterOperation{
.{
.fk = .{
.key = "device_id",
.value = device.id,
},
},
.{
.string = .{
.key = "name",
.value = "ssh",
.comparison = .ie,
},
},
.{
.string = .{
.key = "name",
.value = "telnet",
.comparison = .ie,
},
},
},
},
);
defer service_iter.deinit();
while (try service_iter.next()) |service_result| {
defer service_result.deinit();
switch (service_result) {
.ok => |services| {
for (services.items) |service| {
for (service.ports) |port| {
var addresses = std.ArrayList([]const u8);
errdefer addresses.deinit();
if (device.primary_ip6) |ip| {
log.info("found service {d} {s} {s} {s} {d}", .{ device.id, name, ip.ip(), service.name, port });
try addresses.append(ip.ip());
}
if (device.primary_ip4) |ip| {
log.info("found service {d} {s} {s} {s} {d}", .{ device.id, name, ip.ip(), service.name, port });
try addresses.append(ip.ip());
}
const config: Config = .{
.name = name,
.type = t: {
var output: [32]u8 = undefined;
std.ascii.lowerString(&output, service.name);
break :t try std.meta.stringToEnum(ConnectionType, std.ascii.lowerString(output, service.name));
},
.comment = c: {
const c = try alloc.dupe(u8, name);
std.mem.replaceScalar(u8, c, '-', ' ');
break :c c;
},
.addresses = addresses.toOwnedSlice(),
.port = port,
.username = try alloc.dupe(u8, "jcollie"),
.manufacturer = try alloc.dupe(u8, device.device_type.manufacturer.name),
.model = try alloc.dupe(u8, device.device_type.model),
.part_number = try alloc.dupe(u8, part_number),
.class = c: {
const c = try alloc.dupe(u8, name);
for (c, 0..) |b, i| {
switch (b) {
'a'...'z' => {},
'A'...'Z' => {},
'0'...'9' => {},
'_' => {},
else => c[i] = '_',
}
}
break :c c;
},
};
{
var buf = std.ArrayList(u8).init(alloc);
try std.json.stringify(config, .{}, buf.writer());
}
}
}
},
.err => |err| {
log.err("error from netbox: {s}", .{err.detail});
},
}
}
}
},
.err => |err| {
log.err("error from netbox: {s}", .{err.detail});
return;
},
}
}
}
}