mcp-souschef 3.0.0__py3-none-any.whl → 3.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mcp_souschef-3.0.0.dist-info → mcp_souschef-3.5.1.dist-info}/METADATA +241 -409
- mcp_souschef-3.5.1.dist-info/RECORD +52 -0
- {mcp_souschef-3.0.0.dist-info → mcp_souschef-3.5.1.dist-info}/WHEEL +1 -1
- souschef/__init__.py +2 -10
- souschef/assessment.py +417 -206
- souschef/ci/common.py +1 -1
- souschef/cli.py +302 -19
- souschef/converters/playbook.py +530 -202
- souschef/converters/template.py +122 -5
- souschef/core/__init__.py +6 -1
- souschef/core/ai_schemas.py +81 -0
- souschef/core/http_client.py +394 -0
- souschef/core/logging.py +344 -0
- souschef/core/metrics.py +73 -6
- souschef/core/path_utils.py +233 -19
- souschef/core/url_validation.py +230 -0
- souschef/deployment.py +10 -3
- souschef/generators/__init__.py +13 -0
- souschef/generators/repo.py +695 -0
- souschef/parsers/attributes.py +1 -1
- souschef/parsers/habitat.py +1 -1
- souschef/parsers/inspec.py +25 -2
- souschef/parsers/metadata.py +5 -3
- souschef/parsers/recipe.py +1 -1
- souschef/parsers/resource.py +1 -1
- souschef/parsers/template.py +1 -1
- souschef/server.py +556 -188
- souschef/ui/app.py +44 -36
- souschef/ui/pages/ai_settings.py +151 -30
- souschef/ui/pages/chef_server_settings.py +300 -0
- souschef/ui/pages/cookbook_analysis.py +903 -173
- mcp_souschef-3.0.0.dist-info/RECORD +0 -46
- souschef/converters/cookbook_specific.py.backup +0 -109
- {mcp_souschef-3.0.0.dist-info → mcp_souschef-3.5.1.dist-info}/entry_points.txt +0 -0
- {mcp_souschef-3.0.0.dist-info → mcp_souschef-3.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Chef Server Settings Page for SousChef UI.
|
|
3
|
+
|
|
4
|
+
Configure and validate Chef Server connectivity for dynamic inventory and node queries.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
import streamlit as st
|
|
10
|
+
|
|
11
|
+
from souschef.core.url_validation import validate_user_provided_url
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
import requests
|
|
15
|
+
from requests.exceptions import (
|
|
16
|
+
ConnectionError, # noqa: A004
|
|
17
|
+
Timeout,
|
|
18
|
+
)
|
|
19
|
+
except ImportError:
|
|
20
|
+
requests = None # type: ignore[assignment]
|
|
21
|
+
ConnectionError = Exception # type: ignore[assignment,misc] # noqa: A001
|
|
22
|
+
Timeout = Exception # type: ignore[assignment,misc]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _handle_chef_server_response(
|
|
26
|
+
response: "requests.Response", server_url: str
|
|
27
|
+
) -> tuple[bool, str]:
|
|
28
|
+
"""
|
|
29
|
+
Handle Chef Server search response.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
response: HTTP response from Chef Server
|
|
33
|
+
server_url: The Chef Server URL that was queried
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Tuple of (success: bool, message: str)
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
if response.status_code == 200:
|
|
40
|
+
return True, f"✅ Successfully connected to Chef Server at {server_url}"
|
|
41
|
+
if response.status_code == 401:
|
|
42
|
+
return (
|
|
43
|
+
False,
|
|
44
|
+
"❌ Authentication failed - check your Chef Server credentials",
|
|
45
|
+
)
|
|
46
|
+
if response.status_code == 404:
|
|
47
|
+
return False, "❌ Chef Server search endpoint not found"
|
|
48
|
+
return (
|
|
49
|
+
False,
|
|
50
|
+
f"❌ Connection failed with status code {response.status_code}",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _validate_chef_server_connection(
|
|
55
|
+
server_url: str, node_name: str
|
|
56
|
+
) -> tuple[bool, str]:
|
|
57
|
+
"""
|
|
58
|
+
Validate Chef Server connection by testing the search endpoint.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
server_url: Base URL of the Chef Server
|
|
62
|
+
node_name: Chef node name for authentication
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Tuple of (success: bool, message: str)
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
if not requests:
|
|
69
|
+
return False, "requests library not installed"
|
|
70
|
+
|
|
71
|
+
if not server_url:
|
|
72
|
+
return False, "Server URL is required"
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
server_url = validate_user_provided_url(server_url)
|
|
76
|
+
except ValueError as exc:
|
|
77
|
+
return False, f"Invalid server URL: {exc}"
|
|
78
|
+
|
|
79
|
+
if not node_name:
|
|
80
|
+
return False, "Node name is required for authentication"
|
|
81
|
+
|
|
82
|
+
# Test the search endpoint
|
|
83
|
+
try:
|
|
84
|
+
search_url = f"{server_url.rstrip('/')}/search/node"
|
|
85
|
+
response = requests.get(
|
|
86
|
+
search_url,
|
|
87
|
+
params={"q": "*:*"},
|
|
88
|
+
timeout=5,
|
|
89
|
+
headers={"Accept": "application/json"},
|
|
90
|
+
)
|
|
91
|
+
return _handle_chef_server_response(response, server_url)
|
|
92
|
+
|
|
93
|
+
except Timeout:
|
|
94
|
+
return False, f"❌ Connection timeout - could not reach {server_url}"
|
|
95
|
+
except ConnectionError:
|
|
96
|
+
return False, f"❌ Connection error - Chef Server not reachable at {server_url}"
|
|
97
|
+
except Exception as e:
|
|
98
|
+
return False, f"❌ Unexpected error: {e}"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _render_chef_server_configuration() -> tuple[str, str]:
|
|
102
|
+
"""
|
|
103
|
+
Render Chef Server configuration UI and return config values.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Tuple of (server_url, node_name)
|
|
107
|
+
|
|
108
|
+
"""
|
|
109
|
+
st.subheader("Chef Server Configuration")
|
|
110
|
+
|
|
111
|
+
st.markdown("""
|
|
112
|
+
Configure your Chef Server connection for dynamic inventory generation
|
|
113
|
+
and node queries. This allows SousChef to retrieve live node data from
|
|
114
|
+
your Chef infrastructure.
|
|
115
|
+
""")
|
|
116
|
+
|
|
117
|
+
col1, col2 = st.columns(2)
|
|
118
|
+
|
|
119
|
+
with col1:
|
|
120
|
+
server_url = st.text_input(
|
|
121
|
+
"Chef Server URL",
|
|
122
|
+
help="Full URL of your Chef Server (e.g., https://chef.example.com)",
|
|
123
|
+
key="chef_server_url_input",
|
|
124
|
+
placeholder="https://chef.example.com",
|
|
125
|
+
value=os.environ.get("CHEF_SERVER_URL", ""),
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
with col2:
|
|
129
|
+
node_name = st.text_input(
|
|
130
|
+
"Chef Node Name",
|
|
131
|
+
help="Node name for authentication with Chef Server",
|
|
132
|
+
key="chef_node_name_input",
|
|
133
|
+
placeholder="my-node",
|
|
134
|
+
value=os.environ.get("CHEF_NODE_NAME", ""),
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return server_url, node_name
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _render_test_connection_button(server_url: str, node_name: str) -> None:
|
|
141
|
+
"""
|
|
142
|
+
Render the test connection button and display results.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
server_url: Chef Server URL to test
|
|
146
|
+
node_name: Chef node name for authentication
|
|
147
|
+
|
|
148
|
+
"""
|
|
149
|
+
st.markdown("---")
|
|
150
|
+
st.subheader("Test Connection")
|
|
151
|
+
|
|
152
|
+
col1, col2 = st.columns([1, 3])
|
|
153
|
+
|
|
154
|
+
with col1:
|
|
155
|
+
test_button = st.button(
|
|
156
|
+
"Test Chef Server Connection",
|
|
157
|
+
type="primary",
|
|
158
|
+
help="Verify connectivity to Chef Server",
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
if test_button:
|
|
162
|
+
with col2, st.spinner("Testing Chef Server connection..."):
|
|
163
|
+
success, message = _validate_chef_server_connection(server_url, node_name)
|
|
164
|
+
|
|
165
|
+
if success:
|
|
166
|
+
st.success(message)
|
|
167
|
+
else:
|
|
168
|
+
st.error(message)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _render_usage_examples() -> None:
|
|
172
|
+
"""Render usage examples for Chef Server integration."""
|
|
173
|
+
st.markdown("---")
|
|
174
|
+
st.subheader("Usage Examples")
|
|
175
|
+
|
|
176
|
+
with st.expander("Dynamic Inventory from Chef Searches"):
|
|
177
|
+
st.markdown("""
|
|
178
|
+
Once configured, SousChef can query your Chef Server to generate dynamic
|
|
179
|
+
Ansible inventories based on Chef node searches:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
# Example Chef search query
|
|
183
|
+
search_query = "role:webserver AND chef_environment:production"
|
|
184
|
+
|
|
185
|
+
# SousChef will convert this to an Ansible dynamic inventory
|
|
186
|
+
# that queries your Chef Server in real-time
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Benefits:
|
|
190
|
+
- Real-time node discovery
|
|
191
|
+
- No manual inventory maintenance
|
|
192
|
+
- Leverage existing Chef infrastructure
|
|
193
|
+
- Seamless migration path
|
|
194
|
+
""")
|
|
195
|
+
|
|
196
|
+
with st.expander("Environment Variables"):
|
|
197
|
+
st.markdown("""
|
|
198
|
+
You can also configure Chef Server settings via environment variables:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
export CHEF_SERVER_URL="https://chef.example.com"
|
|
202
|
+
export CHEF_NODE_NAME="my-node"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
These will be automatically detected by SousChef.
|
|
206
|
+
""")
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _render_save_settings_section(server_url: str, node_name: str) -> None:
|
|
210
|
+
"""
|
|
211
|
+
Render the save settings section.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
server_url: Chef Server URL to save
|
|
215
|
+
node_name: Chef node name to save
|
|
216
|
+
|
|
217
|
+
"""
|
|
218
|
+
st.markdown("---")
|
|
219
|
+
st.subheader("Save Settings")
|
|
220
|
+
|
|
221
|
+
col1, col2 = st.columns([1, 3])
|
|
222
|
+
|
|
223
|
+
with col1:
|
|
224
|
+
save_button = st.button(
|
|
225
|
+
"Save Configuration",
|
|
226
|
+
type="primary",
|
|
227
|
+
help="Save Chef Server settings to session",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
if save_button:
|
|
231
|
+
with col2:
|
|
232
|
+
# Save to session state
|
|
233
|
+
st.session_state.chef_server_url = server_url
|
|
234
|
+
st.session_state.chef_node_name = node_name
|
|
235
|
+
|
|
236
|
+
st.success("""
|
|
237
|
+
✅ Chef Server configuration saved to session!
|
|
238
|
+
|
|
239
|
+
**Note:** For persistent configuration across sessions,
|
|
240
|
+
set environment variables:
|
|
241
|
+
- `CHEF_SERVER_URL`
|
|
242
|
+
- `CHEF_NODE_NAME`
|
|
243
|
+
""")
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _render_current_configuration() -> None:
|
|
247
|
+
"""Display current Chef Server configuration from environment or session."""
|
|
248
|
+
current_url = os.environ.get("CHEF_SERVER_URL") or st.session_state.get(
|
|
249
|
+
"chef_server_url", "Not configured"
|
|
250
|
+
)
|
|
251
|
+
current_node = os.environ.get("CHEF_NODE_NAME") or st.session_state.get(
|
|
252
|
+
"chef_node_name", "Not configured"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
st.info(f"""
|
|
256
|
+
**Current Configuration:**
|
|
257
|
+
- Server URL: `{current_url}`
|
|
258
|
+
- Node Name: `{current_node}`
|
|
259
|
+
""")
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def show_chef_server_settings_page() -> None:
|
|
263
|
+
"""Display Chef Server settings and configuration page."""
|
|
264
|
+
st.title("🔧 Chef Server Settings")
|
|
265
|
+
|
|
266
|
+
st.markdown("""
|
|
267
|
+
Configure your Chef Server connection to enable dynamic inventory generation
|
|
268
|
+
and live node queries. This allows SousChef to integrate with your existing
|
|
269
|
+
Chef infrastructure during the migration process.
|
|
270
|
+
""")
|
|
271
|
+
|
|
272
|
+
# Display current configuration
|
|
273
|
+
_render_current_configuration()
|
|
274
|
+
|
|
275
|
+
st.markdown("---")
|
|
276
|
+
|
|
277
|
+
# Configuration inputs
|
|
278
|
+
server_url, node_name = _render_chef_server_configuration()
|
|
279
|
+
|
|
280
|
+
# Test connection
|
|
281
|
+
_render_test_connection_button(server_url, node_name)
|
|
282
|
+
|
|
283
|
+
# Save settings
|
|
284
|
+
_render_save_settings_section(server_url, node_name)
|
|
285
|
+
|
|
286
|
+
# Usage examples
|
|
287
|
+
_render_usage_examples()
|
|
288
|
+
|
|
289
|
+
# Additional information
|
|
290
|
+
st.markdown("---")
|
|
291
|
+
st.markdown("""
|
|
292
|
+
### Security Note
|
|
293
|
+
|
|
294
|
+
Chef Server authentication typically requires:
|
|
295
|
+
- Client key file for API authentication
|
|
296
|
+
- Proper permissions on the Chef Server
|
|
297
|
+
|
|
298
|
+
For production use, ensure your Chef Server credentials are properly secured
|
|
299
|
+
and not committed to version control.
|
|
300
|
+
""")
|