Page MenuHomePhabricator

No OneTemporary

diff --git a/examples/network_get_assignment_example.rs b/crates/store/examples/network_get_assignment_example.rs
similarity index 91%
rename from examples/network_get_assignment_example.rs
rename to crates/store/examples/network_get_assignment_example.rs
index cc5a544..c0438c5 100644
--- a/examples/network_get_assignment_example.rs
+++ b/crates/store/examples/network_get_assignment_example.rs
@@ -1,158 +1,162 @@
use store::{open, Result};
use store::network::{NetRange, BasicProvider, RangeAssigner};
-use std::net::IpAddr;
+
fn main() -> Result<()> {
println!("=== Network Assignment Example ===\n");
// Open the store
let store = open()?;
// Create an IPv4 network with RangeAssigner
let ipv4_netrange = NetRange::from_cidr("192.168.100.0/24")?;
let provider = BasicProvider::new()
.with_config("type", "docker")
.with_config("driver", "bridge");
let assigner = RangeAssigner::new()
.with_config("strategy", "sequential")
.with_config("reserve_gateway", "true");
store.networks().create("docker-bridge", ipv4_netrange, provider, Some(assigner))?;
println!("✓ Created IPv4 network: docker-bridge (192.168.100.0/24)");
// Create an IPv6 network
let ipv6_netrange = NetRange::from_cidr("fd00:db8::/64")?;
let provider6 = BasicProvider::new()
.with_config("type", "kubernetes")
.with_config("driver", "calico");
let assigner6 = RangeAssigner::new()
.with_config("strategy", "sequential");
store.networks().create("k8s-pods", ipv6_netrange, provider6, Some(assigner6))?;
println!("✓ Created IPv6 network: k8s-pods (fd00:db8::/64)");
// Create a network without an assigner
let no_assigner_net = NetRange::from_cidr("10.50.0.0/16")?;
let static_provider = BasicProvider::new()
.with_config("type", "static")
.with_config("manual", "true");
store.networks().create("static-network", no_assigner_net, static_provider, None::<RangeAssigner>)?;
println!("✓ Created static network: static-network (10.50.0.0/16) - no assigner\n");
// Get network instances
let docker_network = store.networks().get("docker-bridge")?.unwrap();
let k8s_network = store.networks().get("k8s-pods")?.unwrap();
let static_network = store.networks().get("static-network")?.unwrap();
// Assign some IPs manually using RangeAssigner
let range_assigner = RangeAssigner::new();
// Docker network assignments
println!("--- Docker Bridge Network Assignments ---");
- if let Some(ref ranges) = store.ranges() {
+ let ranges = store.ranges();
+ {
// Assign IPs to containers
let web_bit = range_assigner.assign_ip("docker-bridge", ranges, "web-container-1")?;
let db_bit = range_assigner.assign_ip("docker-bridge", ranges, "database-container")?;
let cache_bit = range_assigner.assign_ip("docker-bridge", ranges, "redis-cache")?;
println!("Assigned bit positions:");
println!(" web-container-1: bit {}", web_bit);
println!(" database-container: bit {}", db_bit);
println!(" redis-cache: bit {}", cache_bit);
}
// Now use Network.get_assignment to retrieve IP addresses
println!("\nUsing Network.get_assignment() to resolve IPs:");
let containers = ["web-container-1", "database-container", "redis-cache", "nonexistent-container"];
for container in &containers {
- match docker_network.get_assignment(container, store.ranges())? {
+ match docker_network.get_assignment(container, Some(store.ranges()))? {
Some(ip) => println!(" {} -> {}", container, ip),
None => println!(" {} -> No assignment found", container),
}
}
// K8s network assignments
println!("\n--- Kubernetes Pods Network Assignments ---");
- if let Some(ref ranges) = store.ranges() {
+ {
+ let ranges = store.ranges();
range_assigner.assign_ip("k8s-pods", ranges, "nginx-pod-abc123")?;
range_assigner.assign_ip("k8s-pods", ranges, "postgres-pod-def456")?;
range_assigner.assign_ip("k8s-pods", ranges, "api-pod-ghi789")?;
}
let pods = ["nginx-pod-abc123", "postgres-pod-def456", "api-pod-ghi789"];
for pod in &pods {
- if let Some(ip) = k8s_network.get_assignment(pod, store.ranges())? {
+ if let Some(ip) = k8s_network.get_assignment(pod, Some(store.ranges()))? {
println!(" {} -> {}", pod, ip);
}
}
// Test static network (should return None since no assigner)
println!("\n--- Static Network (No Assigner) ---");
- match static_network.get_assignment("some-device", store.ranges())? {
+ match static_network.get_assignment("some-device", Some(store.ranges()))? {
Some(ip) => println!(" Unexpected IP found: {}", ip),
None => println!(" ✓ No assignment found (expected for static network)"),
}
// Demonstrate bit position to IP conversion
println!("\n--- Direct Bit Position to IP Conversion ---");
for bit_pos in 0..5 {
let ipv4_addr = docker_network.get_assignment_by_bit_position(bit_pos)?;
let ipv6_addr = k8s_network.get_assignment_by_bit_position(bit_pos)?;
println!(" Bit {}: IPv4={}, IPv6={}", bit_pos, ipv4_addr, ipv6_addr);
}
// Show practical usage: find all assigned IPs in a network
println!("\n--- All Docker Network Assignments ---");
- if let Some(ref ranges) = store.ranges() {
- let assignments = ranges.list_range("docker-bridge")?;
+ {
+ let ranges = store.ranges();
+ let assignments: Vec<(u64, String)> = ranges.list_range("docker-bridge")?;
for (bit_pos, identifier) in assignments {
let ip = docker_network.get_assignment_by_bit_position(bit_pos)?;
println!(" {}: {} (bit {})", identifier, ip, bit_pos);
}
}
// Demonstrate unassignment and re-query
println!("\n--- Assignment Lifecycle ---");
let test_container = "temporary-container";
// Assign
- if let Some(ref ranges) = store.ranges() {
+ {
+ let ranges = store.ranges();
let bit_pos = range_assigner.assign_ip("docker-bridge", ranges, test_container)?;
- let ip_before = docker_network.get_assignment(test_container, store.ranges())?.unwrap();
+ let ip_before = docker_network.get_assignment(test_container, Some(store.ranges()))?.unwrap();
println!(" Assigned {} -> {} (bit {})", test_container, ip_before, bit_pos);
// Unassign
let unassigned = range_assigner.unassign_ip("docker-bridge", ranges, bit_pos)?;
println!(" Unassigned {}: {}", test_container, unassigned);
// Query after unassignment
- let ip_after = docker_network.get_assignment(test_container, store.ranges())?;
+ let ip_after = docker_network.get_assignment(test_container, Some(store.ranges()))?;
println!(" Query after unassignment: {:?}", ip_after);
}
// Summary
println!("\n=== Summary ===");
let networks = store.networks().list()?;
println!("Created {} networks:", networks.len());
for network_name in networks {
let net = store.networks().get(&network_name)?.unwrap();
let assigner_info = match &net.assigner_type {
Some(atype) => format!("with {} assigner", atype),
None => "no assigner".to_string(),
};
println!(" • {} ({}) - {}", network_name, net.netrange.to_cidr(), assigner_info);
}
println!("\nNetwork.get_assignment() provides a unified interface to:");
println!(" ✓ Query IP assignments by identifier");
println!(" ✓ Support different assigner implementations");
println!(" ✓ Handle both IPv4 and IPv6 networks");
println!(" ✓ Return None for networks without assigners");
println!(" ✓ Convert bit positions to actual IP addresses");
Ok(())
}
\ No newline at end of file
diff --git a/examples/range_assigner_example.rs b/crates/store/examples/range_assigner_example.rs
similarity index 97%
rename from examples/range_assigner_example.rs
rename to crates/store/examples/range_assigner_example.rs
index c90fdc8..311690a 100644
--- a/examples/range_assigner_example.rs
+++ b/crates/store/examples/range_assigner_example.rs
@@ -1,66 +1,66 @@
use store::{open, Result, RangeAssigner};
-use store::network::{NetRange, BasicProvider, NetworkStore};
+use store::network::{NetRange, BasicProvider};
fn main() -> Result<()> {
// Open the store
let store = open()?;
// Create a network with RangeAssigner
let netrange = NetRange::from_cidr("10.0.0.0/24")?;
let provider = BasicProvider::new()
.with_config("type", "docker")
.with_config("subnet", "bridge");
let assigner = RangeAssigner::new()
.with_config("strategy", "sequential")
.with_config("reserve_gateway", "true");
// Create the network - this will automatically initialize the range
store.networks().create("docker-network", netrange, provider, Some(assigner))?;
println!("Created network 'docker-network' with range 10.0.0.0/24");
// Create another RangeAssigner instance to work with the range
let range_assigner = RangeAssigner::new();
let range_name = "docker-network"; // Uses network name as range name
// Assign IP addresses to devices
let container1_ip = range_assigner.assign_ip(range_name, store.ranges(), "container-web-1")?;
let container2_ip = range_assigner.assign_ip(range_name, store.ranges(), "container-db-1")?;
let container3_ip = range_assigner.assign_ip(range_name, store.ranges(), "container-cache-1")?;
println!("Assigned IP addresses:");
println!(" container-web-1: 10.0.0.{}", container1_ip + 1); // +1 to skip network address
println!(" container-db-1: 10.0.0.{}", container2_ip + 1);
println!(" container-cache-1: 10.0.0.{}", container3_ip + 1);
// Retrieve assignment information
let web_assignment = range_assigner.get_assignment_by_bit(range_name, store.ranges(), container1_ip)?;
let db_assignment = range_assigner.get_assignment_by_bit(range_name, store.ranges(), container2_ip)?;
println!("\nAssignment verification:");
println!(" Bit {} assigned to: {:?}", container1_ip, web_assignment);
println!(" Bit {} assigned to: {:?}", container2_ip, db_assignment);
// Unassign an IP (e.g., when container is removed)
let unassigned = range_assigner.unassign_ip(range_name, store.ranges(), container2_ip)?;
println!("\nUnassigned container-db-1: {}", unassigned);
// Verify unassignment
let db_assignment_after = range_assigner.get_assignment_by_bit(range_name, store.ranges(), container2_ip)?;
println!("DB assignment after unassign: {:?}", db_assignment_after);
// Assign a new container to the freed IP
let new_container_ip = range_assigner.assign_ip(range_name, store.ranges(), "container-api-1")?;
println!("New container assigned to bit: {}", new_container_ip);
// List all networks
let networks = store.networks().list()?;
println!("\nAll networks: {:?}", networks);
// Get network details
let network = store.networks().get("docker-network")?.unwrap();
println!("Network details: {:#?}", network);
Ok(())
}
\ No newline at end of file
diff --git a/examples/updated_range_assigner_example.rs b/crates/store/examples/updated_range_assigner_example.rs
similarity index 98%
rename from examples/updated_range_assigner_example.rs
rename to crates/store/examples/updated_range_assigner_example.rs
index 4f8bfa8..5491feb 100644
--- a/examples/updated_range_assigner_example.rs
+++ b/crates/store/examples/updated_range_assigner_example.rs
@@ -1,88 +1,88 @@
use store::{open, Result, RangeAssigner};
-use store::network::{NetRange, BasicProvider, NetworkStore};
+use store::network::{NetRange, BasicProvider};
fn main() -> Result<()> {
// Open the store
let store = open()?;
// Create a network with RangeAssigner
let netrange = NetRange::from_cidr("10.0.0.0/24")?;
let provider = BasicProvider::new()
.with_config("type", "docker")
.with_config("subnet", "bridge");
// RangeAssigner now defaults to using the network name as the range name
let assigner = RangeAssigner::new()
.with_config("strategy", "sequential")
.with_config("reserve_gateway", "true");
// Create the network - range is automatically initialized within the same transaction
store.networks().create("docker-network", netrange, provider, Some(assigner))?;
println!("Created network 'docker-network' with range 10.0.0.0/24");
println!("Range name automatically set to 'docker-network'");
// Create a RangeAssigner instance for IP operations
let range_assigner = RangeAssigner::new();
let network_name = "docker-network"; // This is also the range name
// Assign IP addresses to devices
let container1_ip = range_assigner.assign_ip(network_name, store.ranges(), "container-web-1")?;
let container2_ip = range_assigner.assign_ip(network_name, store.ranges(), "container-db-1")?;
let container3_ip = range_assigner.assign_ip(network_name, store.ranges(), "container-cache-1")?;
println!("\nAssigned IP addresses:");
println!(" container-web-1: 10.0.0.{}", container1_ip + 1); // +1 to skip network address
println!(" container-db-1: 10.0.0.{}", container2_ip + 1);
println!(" container-cache-1: 10.0.0.{}", container3_ip + 1);
// Retrieve assignment information
let web_assignment = range_assigner.get_assignment_by_bit(network_name, store.ranges(), container1_ip)?;
let db_assignment = range_assigner.get_assignment_by_bit(network_name, store.ranges(), container2_ip)?;
println!("\nAssignment verification:");
println!(" Bit {} assigned to: {:?}", container1_ip, web_assignment);
println!(" Bit {} assigned to: {:?}", container2_ip, db_assignment);
// Unassign an IP (e.g., when container is removed)
let unassigned = range_assigner.unassign_ip(network_name, store.ranges(), container2_ip)?;
println!("\nUnassigned container-db-1: {}", unassigned);
// Verify unassignment
let db_assignment_after = range_assigner.get_assignment_by_bit(network_name, store.ranges(), container2_ip)?;
println!("DB assignment after unassign: {:?}", db_assignment_after);
// Assign a new container to the freed IP
let new_container_ip = range_assigner.assign_ip(network_name, store.ranges(), "container-api-1")?;
println!("New container assigned to bit: {}", new_container_ip);
// Example with custom range name
println!("\n--- Example with custom range name ---");
let custom_assigner = RangeAssigner::with_range_name("custom-pool")
.with_config("strategy", "sequential");
let netrange2 = NetRange::from_cidr("172.16.0.0/16")?;
let provider2 = BasicProvider::new().with_config("type", "kubernetes");
store.networks().create("k8s-network", netrange2, provider2, Some(custom_assigner))?;
println!("Created 'k8s-network' with custom range name 'custom-pool'");
// Assign from the custom range
let k8s_assigner = RangeAssigner::new();
let pod_ip = k8s_assigner.assign_ip("custom-pool", store.ranges(), "pod-nginx-1")?;
println!("Assigned pod IP bit position: {}", pod_ip);
// List all networks
let networks = store.networks().list()?;
println!("\nAll networks: {:?}", networks);
// Get network details
let network = store.networks().get("docker-network")?.unwrap();
println!("\nDocker network details:");
println!(" Name: {}", network.name);
println!(" Range: {}", network.netrange.to_cidr());
println!(" Assigner type: {:?}", network.assigner_type);
Ok(())
}
\ No newline at end of file
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
new file mode 100644
index 0000000..336b482
--- /dev/null
+++ b/docs/troubleshooting.md
@@ -0,0 +1,245 @@
+# Troubleshooting Guide
+
+This guide covers common issues you might encounter when working with the collar project and how to resolve them.
+
+## Compilation Issues
+
+### 1. "use of unresolved module or unlinked crate `store`"
+
+**Problem**: Examples fail to compile with errors like:
+```
+error[E0433]: failed to resolve: use of unresolved module or unlinked crate `store`
+```
+
+**Solution**: Make sure you're running examples from the correct package:
+```bash
+# Correct - run from store package
+cargo run --package store --example network_get_assignment_example
+
+# Incorrect - running from workspace root without package specification
+cargo run --example network_get_assignment_example
+```
+
+### 2. Type annotation errors in examples
+
+**Problem**: Examples fail with type inference errors like:
+```
+error[E0282]: type annotations needed
+```
+
+**Solution**: This usually happens when the compiler can't infer the type for generic parameters. Check that:
+- All method calls have the correct parameter types
+- Optional parameters are properly wrapped (e.g., `Some(store.ranges())` instead of `store.ranges()`)
+
+### 3. Missing dependencies
+
+**Problem**: Compilation fails with missing crate errors.
+
+**Solution**: Ensure you're in the correct directory and all dependencies are installed:
+```bash
+cd collar
+cargo check --package store
+```
+
+## Runtime Issues
+
+### 1. Database access errors
+
+**Problem**: Errors related to database file access or permissions.
+
+**Solution**:
+- Ensure the current user has write permissions to the directory
+- Check that no other processes are using the database
+- Try running with elevated permissions if necessary
+
+### 2. Range assignment failures
+
+**Problem**: `RangeFull` errors when assigning IP addresses.
+
+**Solution**:
+- Check the network size vs. number of assignments
+- Use `list_range()` to see current assignments
+- Consider using larger subnets (smaller prefix length)
+
+Example:
+```rust
+// Check how many IPs are available
+let assignments = range_store.list_range("my-network")?;
+println!("Current assignments: {}", assignments.len());
+
+// For /24 network, maximum ~254 usable IPs
+let netrange = NetRange::from_cidr("192.168.1.0/24")?;
+```
+
+### 3. Network assignment returns None
+
+**Problem**: `Network.get_assignment()` returns `None` unexpectedly.
+
+**Solution**: Check that:
+- The network has an assigner configured
+- The identifier exists in the range
+- The RangeStore is properly passed to the method
+
+```rust
+// Debug network configuration
+let network = store.networks().get("my-network")?.unwrap();
+println!("Assigner type: {:?}", network.assigner_type);
+
+// Check if assignment exists
+if let Some(ranges) = store.ranges() {
+ let assignments = ranges.list_range("my-network")?;
+ println!("All assignments: {:?}", assignments);
+}
+```
+
+## Testing Issues
+
+### 1. Tests fail with database conflicts
+
+**Problem**: Tests fail intermittently with database access errors.
+
+**Solution**: Run tests with single thread to avoid conflicts:
+```bash
+cargo test --package store -- --test-threads 1
+```
+
+### 2. Test database cleanup
+
+**Problem**: Previous test runs leave database state that affects new tests.
+
+**Solution**: Tests use temporary directories that should auto-cleanup, but you can manually clean:
+```bash
+# Clean all build artifacts and temporary files
+cargo clean
+rm -rf /tmp/test-*
+```
+
+## Performance Issues
+
+### 1. Slow identifier lookups
+
+**Problem**: `Network.get_assignment()` is slow for large networks.
+
+**Solution**:
+- This is expected for large ranges as it uses O(n) scanning
+- Consider using `get_assignment_by_bit_position()` if you know the bit position
+- For frequently accessed assignments, consider caching
+
+### 2. Large memory usage
+
+**Problem**: High memory usage with large IPv6 networks.
+
+**Solution**:
+- IPv6 ranges are automatically capped at 2^32 addresses
+- Consider using smaller subnets for very large deployments
+- Monitor actual usage vs. allocated range size
+
+## Common Patterns and Solutions
+
+### 1. Proper error handling
+
+```rust
+// Good: Handle specific error types
+match range_assigner.assign_ip("network", store.ranges(), "device") {
+ Ok(bit_pos) => println!("Assigned: {}", bit_pos),
+ Err(Error::RangeFull(range_name)) => {
+ eprintln!("Range '{}' is full", range_name);
+ // Handle gracefully - maybe use different network
+ }
+ Err(e) => eprintln!("Unexpected error: {:?}", e),
+}
+```
+
+### 2. Network lifecycle management
+
+```rust
+// Create network with proper cleanup
+let network_name = "temp-network";
+
+// Create
+store.networks().create(network_name, netrange, provider, Some(assigner))?;
+
+// Use
+let assignments = /* ... */;
+
+// Cleanup (manual - consider adding to NetworkStore)
+// Note: Currently no automatic range cleanup when network is deleted
+if let Some(ranges) = store.ranges() {
+ // Would need custom cleanup logic here
+}
+```
+
+### 3. Checking network capacity
+
+```rust
+fn check_network_capacity(network_name: &str, ranges: &RangeStore) -> Result<(usize, u64)> {
+ let assignments = ranges.list_range(network_name)?;
+ let used = assignments.len();
+
+ // Get network info to calculate total capacity
+ // This would require additional method to get range size
+ // For now, calculate from CIDR manually
+
+ Ok((used, 256)) // Example for /24 network
+}
+```
+
+## Getting Help
+
+### 1. Enable logging
+
+Add logging to see what's happening:
+```rust
+env_logger::init();
+log::info!("Creating network: {}", network_name);
+```
+
+### 2. Debug network state
+
+```rust
+// Check network configuration
+let network = store.networks().get("my-network")?.unwrap();
+println!("Network: {:#?}", network);
+
+// Check range assignments
+if let Some(ranges) = store.ranges() {
+ let assignments = ranges.list_range("my-network")?;
+ for (bit, id) in assignments {
+ let ip = network.get_assignment_by_bit_position(bit)?;
+ println!(" {} -> {} (bit {})", id, ip, bit);
+ }
+}
+```
+
+### 3. Validate network configuration
+
+```rust
+// Check that network CIDR is valid
+let netrange = NetRange::from_cidr("192.168.1.0/24")?;
+println!("Network: {}", netrange.to_cidr());
+
+// Verify assigner type matches expectations
+if let Some(assigner_type) = &network.assigner_type {
+ println!("Using assigner: {}", assigner_type);
+} else {
+ println!("No assigner configured - assignments will return None");
+}
+```
+
+## Best Practices
+
+1. **Always check return values** - Many methods return `Option` or `Result`
+2. **Use appropriate network sizes** - Don't allocate huge ranges unless needed
+3. **Test with small ranges first** - Easier to debug with /29 or /28 networks
+4. **Clean up assignments** - Unassign IPs when devices are removed
+5. **Handle range exhaustion gracefully** - Have fallback networks or error handling
+6. **Use descriptive identifiers** - Makes debugging easier
+
+## Common Error Messages
+
+| Error | Meaning | Solution |
+|-------|---------|----------|
+| `RangeFull` | No free IPs in range | Use larger subnet or clean up unused assignments |
+| `NamespaceKeyReserved` | Network name already exists | Use different name or delete existing network |
+| `BitOutOfRange` | Bit position exceeds range size | Check range size and bit position validity |
+| `InvalidCidr` | CIDR format is wrong | Use correct format like "192.168.1.0/24" |
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jun 9, 2:01 PM (22 m, 41 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
47596
Default Alt Text
(23 KB)

Event Timeline