Skip to content

Commit eebdc89

Browse files
authored
Merge pull request #1190 from rackerlabs/configure-svm-ips
feat: Configure LIFs and SVM on NetApp
2 parents 5ac1672 + b46c60e commit eebdc89

37 files changed

+10114
-357
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Example NetApp configuration file showing the new netapp_nic_slot_prefix option
2+
3+
[netapp_nvme]
4+
# Required configuration options
5+
netapp_server_hostname = netapp-cluster.example.com
6+
netapp_login = admin
7+
netapp_password = your-secure-password
8+
9+
# Optional: NIC slot prefix for port naming (defaults to 'e4' if not specified)
10+
# This controls the base port name generation in NetappIPInterfaceConfig
11+
# Examples:
12+
# netapp_nic_slot_prefix = e4 # Results in ports like e4a, e4b (default)
13+
# netapp_nic_slot_prefix = e5 # Results in ports like e5a, e5b
14+
# netapp_nic_slot_prefix = e6 # Results in ports like e6a, e6b
15+
netapp_nic_slot_prefix = e5
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# NetApp Manager Architecture
2+
3+
## Overview
4+
5+
The NetApp Manager uses a layered architecture with dependency injection, providing maintainability, testability, and separation of concerns.
6+
7+
## Architecture Layers
8+
9+
### 1. NetAppManager (Orchestration Layer)
10+
11+
- **File**: `netapp_manager.py`
12+
- **Purpose**: Orchestrates operations across multiple services
13+
- **Key Features**:
14+
- Maintains all existing public method signatures
15+
- Delegates operations to appropriate service layers
16+
- Handles cross-service coordination (e.g., cleanup operations)
17+
- Manages dependency injection for all services
18+
19+
### 2. Service Layer
20+
21+
- **Files**: `netapp_svm_service.py`, `netapp_volume_service.py`, `netapp_lif_service.py`
22+
- **Purpose**: Implements business logic and naming conventions for specific NetApp resource types
23+
- **Key Features**:
24+
- Encapsulates business rules (e.g., SVM naming: `os-{project_id}`)
25+
- Handles resource-specific operations and validation
26+
- Provides clean interfaces for the orchestration layer
27+
- 100% test coverage with mocked dependencies
28+
29+
### 3. Client Abstraction Layer
30+
31+
- **File**: `netapp_client.py`
32+
- **Purpose**: Provides a thin abstraction over the NetApp ONTAP SDK
33+
- **Key Features**:
34+
- Converts between value objects and SDK objects
35+
- Handles low-level NetApp API interactions
36+
- Implements the NetAppClientInterface for testability
37+
- Manages SDK connection lifecycle
38+
39+
### 4. Infrastructure Components
40+
41+
#### Configuration Management
42+
43+
- **File**: `netapp_config.py`
44+
- **Purpose**: Centralized configuration parsing and validation
45+
- **Features**: Type-safe configuration with validation
46+
47+
#### Error Handling
48+
49+
- **File**: `netapp_error_handler.py`
50+
- **Purpose**: Centralized error handling and logging
51+
- **Features**: Context-aware error translation and structured logging
52+
53+
#### Value Objects
54+
55+
- **File**: `netapp_value_objects.py`
56+
- **Purpose**: Immutable data structures for NetApp operations
57+
- **Features**: Type-safe specifications and results for all operations
58+
59+
#### Custom Exceptions
60+
61+
- **File**: `netapp_exceptions.py`
62+
- **Purpose**: Domain-specific exception hierarchy
63+
- **Features**: Structured error information with context
64+
65+
## Dependency Flow
66+
67+
```text
68+
NetAppManager
69+
├── SvmService ──────┐
70+
├── VolumeService ───┼── NetAppClient ── NetApp SDK
71+
├── LifService ──────┘
72+
├── NetAppConfig
73+
└── ErrorHandler
74+
```
75+
76+
## Key Benefits
77+
78+
### 1. Maintainability
79+
80+
- Clear separation of concerns
81+
- Single responsibility principle
82+
- Dependency injection enables easy component replacement
83+
84+
### 2. Testability
85+
86+
- Each layer can be tested in isolation
87+
- Service layer has 100% test coverage
88+
- Mock-friendly interfaces reduce test complexity
89+
90+
### 3. API Stability
91+
92+
- All existing NetAppManager public methods unchanged
93+
- Same method signatures and return values
94+
- Existing code continues to work without modification
95+
96+
### 4. Extensibility
97+
98+
- New NetApp operations can be added at the appropriate layer
99+
- Business logic changes isolated to service layer
100+
- SDK changes isolated to client layer
101+
102+
## Usage Examples
103+
104+
### Basic Usage (Unchanged)
105+
106+
```python
107+
# Existing code continues to work
108+
manager = NetAppManager("/path/to/config.conf")
109+
svm_name = manager.create_svm("project-123", "aggregate1")
110+
volume_name = manager.create_volume("project-123", "1TB", "aggregate1")
111+
```
112+
113+
### Advanced Usage with Dependency Injection
114+
115+
```python
116+
# For testing or custom configurations
117+
config = NetAppConfig("/custom/config.conf")
118+
error_handler = ErrorHandler()
119+
client = NetAppClient(config, error_handler)
120+
svm_service = SvmService(client, error_handler)
121+
122+
# Use services directly if needed
123+
svm_name = svm_service.create_svm("project-123", "aggregate1")
124+
```
125+
126+
## Testing Strategy
127+
128+
### Unit Tests
129+
130+
- Each service tested with mocked NetAppClient
131+
- Value objects tested for validation and immutability
132+
- Configuration and error handling tested independently
133+
134+
### Integration Tests
135+
136+
- NetAppManager tested with mocked services
137+
- Cross-service coordination tested (e.g., cleanup operations)
138+
- API compatibility verified
139+
140+
## Potential Future Enhancements
141+
142+
The new architecture enables several future improvements:
143+
144+
1. **Async Operations**: Service layer can be enhanced with async/await
145+
2. **Caching**: Client layer can add intelligent caching
146+
3. **Metrics**: Error handler can emit metrics for monitoring
147+
4. **Multi-tenancy**: Service layer can handle multiple NetApp clusters
148+
5. **Configuration Hot-reload**: Config layer can support dynamic updates

python/understack-workflows/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ bmc-kube-password = "understack_workflows.main.bmc_display_password:main"
4040
sync-network-segment-range = "understack_workflows.main.sync_ucvni_group_range:main"
4141
openstack-oslo-event = "understack_workflows.main.openstack_oslo_event:main"
4242
netapp-create-svm = "understack_workflows.main.netapp_create_svm:main"
43+
netapp-configure-interfaces = "understack_workflows.main.netapp_configure_net:main"
4344

4445
[dependency-groups]
4546
test = [
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"data": {
3+
"virtual_machines": [
4+
{
5+
"interfaces": [
6+
{
7+
"name": "N1-lif-A",
8+
"ip_addresses": [
9+
{
10+
"address": "100.127.0.21/29"
11+
}
12+
],
13+
"tagged_vlans": [
14+
{
15+
"vid": 2002
16+
}
17+
]
18+
},
19+
{
20+
"name": "N1-lif-B",
21+
"ip_addresses": [
22+
{
23+
"address": "100.127.128.21/29"
24+
}
25+
],
26+
"tagged_vlans": [
27+
{
28+
"vid": 2002
29+
}
30+
]
31+
},
32+
{
33+
"name": "N2-lif-A",
34+
"ip_addresses": [
35+
{
36+
"address": "100.127.0.22/29"
37+
}
38+
],
39+
"tagged_vlans": [
40+
{
41+
"vid": 2002
42+
}
43+
]
44+
},
45+
{
46+
"name": "N2-lif-B",
47+
"ip_addresses": [
48+
{
49+
"address": "100.127.128.22/29"
50+
}
51+
],
52+
"tagged_vlans": [
53+
{
54+
"vid": 2002
55+
}
56+
]
57+
}
58+
]
59+
}
60+
]
61+
}
62+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"data": {
3+
"virtual_machines": []
4+
}
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"errors": [
3+
{
4+
"message": "GraphQL syntax error"
5+
}
6+
]
7+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"data": {
3+
"virtual_machines": [
4+
{
5+
"interfaces": [
6+
{
7+
"name": "invalid-interface",
8+
"ip_addresses": [
9+
{
10+
"address": "192.168.1.10/24"
11+
},
12+
{
13+
"address": "192.168.1.11/24"
14+
}
15+
],
16+
"tagged_vlans": [
17+
{
18+
"vid": 100
19+
}
20+
]
21+
}
22+
]
23+
}
24+
]
25+
}
26+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"data": {
3+
"virtual_machines": [
4+
{
5+
"interfaces": [
6+
{
7+
"name": "N1-lif-A",
8+
"ip_addresses": [
9+
{
10+
"address": "100.127.0.21/29"
11+
}
12+
],
13+
"tagged_vlans": [
14+
{
15+
"vid": 2002
16+
}
17+
]
18+
},
19+
{
20+
"name": "N1-lif-B",
21+
"ip_addresses": [
22+
{
23+
"address": "100.127.128.21/29"
24+
}
25+
],
26+
"tagged_vlans": [
27+
{
28+
"vid": 2002
29+
}
30+
]
31+
}
32+
]
33+
}
34+
]
35+
}
36+
}

0 commit comments

Comments
 (0)