Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F73783
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
23 KB
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
rCOLLAR collar
Event Timeline
Log In to Comment