cloudmesh-ai-common 7.0.4__tar.gz
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.
- cloudmesh_ai_common-7.0.4/PKG-INFO +20 -0
- cloudmesh_ai_common-7.0.4/README.md +104 -0
- cloudmesh_ai_common-7.0.4/VERSION +1 -0
- cloudmesh_ai_common-7.0.4/pyproject.toml +55 -0
- cloudmesh_ai_common-7.0.4/setup.cfg +4 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh/ai/common/__init__.py +48 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh/ai/common/aggregation.py +130 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh/ai/common/io.py +101 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh/ai/common/logging.py +264 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh/ai/common/stopwatch.py +407 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh/ai/common/sys.py +589 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh/ai/common/telemetry.py +408 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh/ai/common/time.py +35 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh/ai/common/user.py +87 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh_ai_common.egg-info/PKG-INFO +20 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh_ai_common.egg-info/SOURCES.txt +26 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh_ai_common.egg-info/dependency_links.txt +1 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh_ai_common.egg-info/requires.txt +15 -0
- cloudmesh_ai_common-7.0.4/src/cloudmesh_ai_common.egg-info/top_level.txt +1 -0
- cloudmesh_ai_common-7.0.4/tests/test_gpu_detection.py +72 -0
- cloudmesh_ai_common-7.0.4/tests/test_io.py +85 -0
- cloudmesh_ai_common-7.0.4/tests/test_logging.py +31 -0
- cloudmesh_ai_common-7.0.4/tests/test_shell.py +21 -0
- cloudmesh_ai_common-7.0.4/tests/test_stopwatch_threadsafe.py +84 -0
- cloudmesh_ai_common-7.0.4/tests/test_sys.py +75 -0
- cloudmesh_ai_common-7.0.4/tests/test_telemetry_integration.py +125 -0
- cloudmesh_ai_common-7.0.4/tests/test_time.py +14 -0
- cloudmesh_ai_common-7.0.4/tests/test_user.py +66 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cloudmesh-ai-common
|
|
3
|
+
Version: 7.0.4
|
|
4
|
+
Summary: CMC: Cloudmesh Command for AI
|
|
5
|
+
License: Apache-2.0
|
|
6
|
+
Keywords: cmc,extension,cli,click,cloudmesh
|
|
7
|
+
Requires-Dist: click
|
|
8
|
+
Requires-Dist: rich
|
|
9
|
+
Requires-Dist: shellingham
|
|
10
|
+
Requires-Dist: psutil
|
|
11
|
+
Requires-Dist: PyYAML
|
|
12
|
+
Requires-Dist: humanize
|
|
13
|
+
Requires-Dist: tzlocal
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest; extra == "dev"
|
|
16
|
+
Requires-Dist: pip-tools; extra == "dev"
|
|
17
|
+
Requires-Dist: twine; extra == "dev"
|
|
18
|
+
Requires-Dist: ruff; extra == "dev"
|
|
19
|
+
Requires-Dist: mypy; extra == "dev"
|
|
20
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Cloudmesh AI Common
|
|
2
|
+
|
|
3
|
+
`cloudmesh-ai-common` provides a set of shared utilities for the Cloudmesh AI ecosystem, focusing on system introspection, structured telemetry, and standardized logging.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### 1. Enhanced System Introspection (`cloudmesh.ai.common.sys`)
|
|
8
|
+
The system utility provides deep insights into the host hardware and environment.
|
|
9
|
+
|
|
10
|
+
- **Hardware Detection**:
|
|
11
|
+
- **GPU**: Automatic detection for NVIDIA, AMD, Apple Silicon, and Intel GPUs.
|
|
12
|
+
- **Topology**: Detection of NUMA nodes and high-speed network interfaces (InfiniBand/RoCE).
|
|
13
|
+
- **CPU**: Detailed processor descriptions across macOS, Windows, and Linux.
|
|
14
|
+
- **Thermal Monitoring**: Standardized CPU temperature retrieval across Linux and macOS to detect thermal throttling.
|
|
15
|
+
- **Container Awareness**: Automatic detection of Docker and Kubernetes environments, including extraction of K8s namespace metadata.
|
|
16
|
+
- **Real-time Metrics**:
|
|
17
|
+
- Live CPU utilization (overall and per-core).
|
|
18
|
+
- Detailed memory and swap usage.
|
|
19
|
+
- Disk I/O statistics and usage.
|
|
20
|
+
- **System Info**: The `systeminfo()` function collects a comprehensive snapshot of the environment. Use `realtime=True` to include live performance metrics.
|
|
21
|
+
|
|
22
|
+
### 2. Advanced Telemetry System (`cloudmesh.ai.common.telemetry`)
|
|
23
|
+
A pluggable telemetry framework for emitting structured performance and status data from AI commands.
|
|
24
|
+
|
|
25
|
+
- **Pluggable Backends**:
|
|
26
|
+
- `JSONFileBackend`: Emits records in JSONL format for easy ingestion by log aggregators.
|
|
27
|
+
- `SQLiteBackend`: Stores telemetry in a structured SQLite database for complex querying.
|
|
28
|
+
- `TextBackend`: Provides human-readable summaries for developers and operators.
|
|
29
|
+
- **Automatic Tracking**: The `track()` context manager automatically handles start/complete/fail events and calculates task duration.
|
|
30
|
+
- **Async Support**: The `AsyncTelemetry` class allows non-blocking telemetry emission using `asyncio`, ensuring that I/O operations do not interfere with compute-intensive AI tasks.
|
|
31
|
+
- **Standardized Events**: Built-in helpers for `start()`, `complete()`, and `fail()` events.
|
|
32
|
+
|
|
33
|
+
### 3. Telemetry Aggregation (`cloudmesh.ai.common.aggregation`)
|
|
34
|
+
The `TelemetryAggregator` utility allows for the analysis of emitted telemetry data.
|
|
35
|
+
|
|
36
|
+
- **Multi-source Loading**: Load data from either JSONL files or SQLite databases.
|
|
37
|
+
- **Statistical Summaries**: Calculate success rates, status distributions, and command frequency.
|
|
38
|
+
- **Metric Analysis**: Aggregate specific KPIs to find average, minimum, and maximum values across multiple runs.
|
|
39
|
+
|
|
40
|
+
### 4. Standardized Logging (`cloudmesh.ai.common.logging`)
|
|
41
|
+
Provides a consistent logging interface across all AI components to ensure uniform log formatting and traceability.
|
|
42
|
+
|
|
43
|
+
## Usage Examples
|
|
44
|
+
|
|
45
|
+
### System Info
|
|
46
|
+
```python
|
|
47
|
+
from cloudmesh.ai.common import sys as ai_sys
|
|
48
|
+
|
|
49
|
+
# Get static and real-time system info
|
|
50
|
+
info = ai_sys.systeminfo(realtime=True)
|
|
51
|
+
print(f"CPU: {info['cpu']}")
|
|
52
|
+
print(f"GPU Present: {info['gpu.present']}")
|
|
53
|
+
print(f"CPU Temp: {info.get('cpu.temp')}")
|
|
54
|
+
print(f"Container: {info.get('container.type', 'none')}")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Synchronous Telemetry with Context Manager
|
|
58
|
+
```python
|
|
59
|
+
from cloudmesh.ai.common.telemetry import Telemetry, SQLiteBackend, TextBackend
|
|
60
|
+
|
|
61
|
+
telemetry = Telemetry(
|
|
62
|
+
"my-ai-command",
|
|
63
|
+
backends=[SQLiteBackend("metrics.db"), TextBackend()]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Use the track context manager for automatic timing and error handling
|
|
67
|
+
with telemetry.track(message="Running inference", metrics={"model": "llama-3"}):
|
|
68
|
+
# ... perform work ...
|
|
69
|
+
# If an exception occurs here, it is automatically logged as a 'failed' event
|
|
70
|
+
pass
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Asynchronous Telemetry
|
|
74
|
+
```python
|
|
75
|
+
import asyncio
|
|
76
|
+
from cloudmesh.ai.common.telemetry import AsyncTelemetry, JSONFileBackend
|
|
77
|
+
|
|
78
|
+
async def run_command():
|
|
79
|
+
telemetry = AsyncTelemetry(
|
|
80
|
+
"async-ai-task",
|
|
81
|
+
backends=[JSONFileBackend("async_metrics.jsonl")]
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
async with telemetry.track(message="Processing async request"):
|
|
85
|
+
# ... perform async work ...
|
|
86
|
+
await asyncio.sleep(0.1)
|
|
87
|
+
|
|
88
|
+
asyncio.run(run_command())
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Telemetry Aggregation
|
|
92
|
+
```python
|
|
93
|
+
from cloudmesh.ai.common.aggregation import TelemetryAggregator
|
|
94
|
+
|
|
95
|
+
# Analyze data from a SQLite database
|
|
96
|
+
agg = TelemetryAggregator("metrics.db")
|
|
97
|
+
|
|
98
|
+
# Get high-level summary
|
|
99
|
+
summary = agg.get_summary()
|
|
100
|
+
print(f"Success Rate: {summary['success_rate']}")
|
|
101
|
+
|
|
102
|
+
# Aggregate a specific metric across all runs
|
|
103
|
+
latency_stats = agg.aggregate_metric("duration_sec")
|
|
104
|
+
print(f"Average Duration: {latency_stats['avg']}s")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
7.0.4
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cloudmesh-ai-common"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "CMC: Cloudmesh Command for AI"
|
|
9
|
+
license = {text = "Apache-2.0"}
|
|
10
|
+
keywords = ["cmc", "extension", "cli", "click", "cloudmesh"]
|
|
11
|
+
dependencies = [
|
|
12
|
+
"click",
|
|
13
|
+
"rich",
|
|
14
|
+
"shellingham",
|
|
15
|
+
"psutil",
|
|
16
|
+
"PyYAML",
|
|
17
|
+
"humanize",
|
|
18
|
+
"tzlocal",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
dev = [
|
|
23
|
+
"pytest",
|
|
24
|
+
"pip-tools",
|
|
25
|
+
"twine",
|
|
26
|
+
"ruff",
|
|
27
|
+
"mypy",
|
|
28
|
+
"pytest-asyncio",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.dynamic]
|
|
32
|
+
version = {file = ["VERSION"]}
|
|
33
|
+
|
|
34
|
+
[tool.setuptools]
|
|
35
|
+
# Tells setuptools to look inside the 'src' directory for packages
|
|
36
|
+
package-dir = {"" = "src"}
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
where = ["src"]
|
|
40
|
+
include = ["cloudmesh*"]
|
|
41
|
+
|
|
42
|
+
[tool.ruff]
|
|
43
|
+
line-length = 100
|
|
44
|
+
target-version = "py310"
|
|
45
|
+
|
|
46
|
+
[tool.ruff.lint]
|
|
47
|
+
select = ["E", "F", "W", "I", "N", "UP"]
|
|
48
|
+
ignore = ["E501"]
|
|
49
|
+
|
|
50
|
+
[tool.mypy]
|
|
51
|
+
python_version = "3.10"
|
|
52
|
+
strict = false
|
|
53
|
+
ignore_missing_imports = true
|
|
54
|
+
warn_return_any = true
|
|
55
|
+
warn_unused_configs = true
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Common utilities for cloudmesh-ai components.
|
|
2
|
+
|
|
3
|
+
This package provides shared functionality for logging, telemetry, system
|
|
4
|
+
information gathering, and other common helper utilities used across
|
|
5
|
+
the cloudmesh-ai ecosystem.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .logging import (
|
|
9
|
+
set_context_id,
|
|
10
|
+
get_context_id,
|
|
11
|
+
ContextFilter,
|
|
12
|
+
JsonFormatter,
|
|
13
|
+
load_logging_config,
|
|
14
|
+
get_log_dir,
|
|
15
|
+
ensure_log_dir,
|
|
16
|
+
get_log_file_path,
|
|
17
|
+
get_logger,
|
|
18
|
+
progress,
|
|
19
|
+
)
|
|
20
|
+
from .aggregation import TelemetryAggregator
|
|
21
|
+
from .telemetry import (
|
|
22
|
+
TelemetryBackend,
|
|
23
|
+
JSONFileBackend,
|
|
24
|
+
SQLiteBackend,
|
|
25
|
+
TextBackend,
|
|
26
|
+
Telemetry,
|
|
27
|
+
AsyncTelemetry,
|
|
28
|
+
)
|
|
29
|
+
from .sys import (
|
|
30
|
+
os_is_windows,
|
|
31
|
+
os_is_mac,
|
|
32
|
+
os_is_linux,
|
|
33
|
+
os_is_pi,
|
|
34
|
+
has_window_manager,
|
|
35
|
+
sys_user,
|
|
36
|
+
get_platform,
|
|
37
|
+
get_cpu_description,
|
|
38
|
+
get_gpu_info,
|
|
39
|
+
get_thermal_info,
|
|
40
|
+
get_numa_info,
|
|
41
|
+
get_container_info,
|
|
42
|
+
get_network_info,
|
|
43
|
+
get_disk_read_speed,
|
|
44
|
+
get_cpu_metrics,
|
|
45
|
+
get_memory_metrics,
|
|
46
|
+
get_disk_metrics,
|
|
47
|
+
systeminfo,
|
|
48
|
+
)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Telemetry aggregation utility for cloudmesh-ai.
|
|
3
|
+
Provides tools to analyze and summarize telemetry data from various backends.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import sqlite3
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Dict, Any, List, Optional, Union
|
|
10
|
+
from collections import defaultdict
|
|
11
|
+
|
|
12
|
+
class TelemetryAggregator:
|
|
13
|
+
"""
|
|
14
|
+
Analyzes telemetry records to provide summaries and statistics.
|
|
15
|
+
Supports loading data from both JSONL files and SQLite databases.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, source: Union[str, Path]):
|
|
19
|
+
"""
|
|
20
|
+
Initialize the TelemetryAggregator.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
source: Path to the telemetry source (JSONL file or SQLite .db file).
|
|
24
|
+
"""
|
|
25
|
+
self.source = Path(source).expanduser()
|
|
26
|
+
self.records: List[Dict[str, Any]] = []
|
|
27
|
+
self._load_data()
|
|
28
|
+
|
|
29
|
+
def _load_data(self) -> None:
|
|
30
|
+
"""Detects source type and loads records into memory.
|
|
31
|
+
"""
|
|
32
|
+
if self.source.suffix == ".db":
|
|
33
|
+
self._load_from_sqlite()
|
|
34
|
+
else:
|
|
35
|
+
self._load_from_jsonl()
|
|
36
|
+
|
|
37
|
+
def _load_from_jsonl(self) -> None:
|
|
38
|
+
"""Loads records from a JSONL file.
|
|
39
|
+
"""
|
|
40
|
+
try:
|
|
41
|
+
if not self.source.exists():
|
|
42
|
+
return
|
|
43
|
+
with open(self.source, "r") as f:
|
|
44
|
+
for line in f:
|
|
45
|
+
if line.strip():
|
|
46
|
+
self.records.append(json.loads(line))
|
|
47
|
+
except Exception as e:
|
|
48
|
+
print(f"Error loading JSONL telemetry: {e}")
|
|
49
|
+
|
|
50
|
+
def _load_from_sqlite(self) -> None:
|
|
51
|
+
"""Loads records from a SQLite database.
|
|
52
|
+
"""
|
|
53
|
+
try:
|
|
54
|
+
with sqlite3.connect(self.source) as conn:
|
|
55
|
+
conn.row_factory = sqlite3.Row
|
|
56
|
+
cursor = conn.execute("SELECT * FROM telemetry")
|
|
57
|
+
for row in cursor:
|
|
58
|
+
record = dict(row)
|
|
59
|
+
# Convert JSON strings back to dicts
|
|
60
|
+
record["metrics"] = json.loads(record["metrics"]) if isinstance(record["metrics"], str) else record["metrics"]
|
|
61
|
+
record["system"] = json.loads(record["system"]) if isinstance(record["system"], str) else record["system"]
|
|
62
|
+
self.records.append(record)
|
|
63
|
+
except Exception as e:
|
|
64
|
+
print(f"Error loading SQLite telemetry: {e}")
|
|
65
|
+
|
|
66
|
+
def get_summary(self) -> Dict[str, Any]:
|
|
67
|
+
"""
|
|
68
|
+
Calculates a high-level summary of the telemetry data.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
A dictionary containing total records, success rate,
|
|
72
|
+
status distribution, and command distribution.
|
|
73
|
+
"""
|
|
74
|
+
if not self.records:
|
|
75
|
+
return {"error": "No records found"}
|
|
76
|
+
|
|
77
|
+
total = len(self.records)
|
|
78
|
+
status_counts = defaultdict(int)
|
|
79
|
+
command_counts = defaultdict(int)
|
|
80
|
+
|
|
81
|
+
for r in self.records:
|
|
82
|
+
status_counts[r.get("status", "unknown")] += 1
|
|
83
|
+
command_counts[r.get("command", "unknown")] += 1
|
|
84
|
+
|
|
85
|
+
success_count = status_counts.get("completed", 0)
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
"total_records": total,
|
|
89
|
+
"success_rate": f"{(success_count / total) * 100:.2f}%",
|
|
90
|
+
"status_distribution": dict(status_counts),
|
|
91
|
+
"command_distribution": dict(command_counts),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
def aggregate_metric(self, metric_name: str) -> Dict[str, Any]:
|
|
95
|
+
"""
|
|
96
|
+
Calculates average, min, and max for a specific metric across all records.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
metric_name: The key of the metric to aggregate from the 'metrics' dictionary.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
A dictionary containing the count, average, minimum, and maximum values.
|
|
103
|
+
"""
|
|
104
|
+
values = []
|
|
105
|
+
for r in self.records:
|
|
106
|
+
metrics = r.get("metrics", {})
|
|
107
|
+
if metric_name in metrics:
|
|
108
|
+
val = metrics[metric_name]
|
|
109
|
+
if isinstance(val, (int, float)):
|
|
110
|
+
values.append(val)
|
|
111
|
+
|
|
112
|
+
if not values:
|
|
113
|
+
return {"metric": metric_name, "status": "no data"}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
"metric": metric_name,
|
|
117
|
+
"count": len(values),
|
|
118
|
+
"avg": sum(values) / len(values),
|
|
119
|
+
"min": min(values),
|
|
120
|
+
"max": max(values),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if __name__ == "__main__":
|
|
124
|
+
# Simple test if run directly
|
|
125
|
+
import sys
|
|
126
|
+
if len(sys.argv) > 1:
|
|
127
|
+
agg = TelemetryAggregator(sys.argv[1])
|
|
128
|
+
print(json.dumps(agg.get_summary(), indent=4))
|
|
129
|
+
else:
|
|
130
|
+
print("Usage: python aggregation.py <telemetry_file_or_db>")
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
I/O utility functions for cloudmesh-ai.
|
|
3
|
+
Provides helpers for path expansion, YAML handling, and benchmark file creation.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import yaml
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
|
|
11
|
+
def path_expand(text: str, slashreplace: bool = True) -> str:
|
|
12
|
+
"""Expands a path string by resolving '~', environment variables, and relative links.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
text: The path to be expanded (e.g., "~/$PROJECT/./file.txt").
|
|
16
|
+
slashreplace: If True, returns backslashes on Windows. Defaults to True.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
The fully expanded and absolute path.
|
|
20
|
+
"""
|
|
21
|
+
if not text:
|
|
22
|
+
return ""
|
|
23
|
+
|
|
24
|
+
# 1. Expand ~ and Environment Variables
|
|
25
|
+
expanded = os.path.expandvars(os.path.expanduser(text))
|
|
26
|
+
|
|
27
|
+
# 2. Convert to a Path object and make it absolute
|
|
28
|
+
# .resolve() handles the "./" and "../" logic correctly
|
|
29
|
+
path_obj = Path(expanded).resolve()
|
|
30
|
+
|
|
31
|
+
# 3. Handle string conversion and slash preference
|
|
32
|
+
if slashreplace and os.name == 'nt':
|
|
33
|
+
# On Windows, this automatically uses backslashes
|
|
34
|
+
return str(path_obj)
|
|
35
|
+
|
|
36
|
+
# .as_posix() forces forward slashes (/) regardless of OS
|
|
37
|
+
return path_obj.as_posix()
|
|
38
|
+
|
|
39
|
+
def load_yaml(path: Path) -> Optional[Dict[str, Any]]:
|
|
40
|
+
"""Safely loads a YAML file from the given path.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
path: Path to the YAML file.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
The loaded YAML data as a dictionary, or None if the file does not exist
|
|
47
|
+
or an error occurs.
|
|
48
|
+
"""
|
|
49
|
+
try:
|
|
50
|
+
if not path.exists():
|
|
51
|
+
return None
|
|
52
|
+
with open(path, 'r') as f:
|
|
53
|
+
return yaml.safe_load(f)
|
|
54
|
+
except (yaml.YAMLError, OSError):
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
def dump_yaml(path: Path, data: Dict[str, Any]) -> None:
|
|
58
|
+
"""Safely writes a dictionary to a YAML file, ensuring the directory exists.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
path: Path where the YAML file should be written.
|
|
62
|
+
data: The dictionary to write to the file.
|
|
63
|
+
|
|
64
|
+
"""
|
|
65
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
66
|
+
with open(path, 'w') as f:
|
|
67
|
+
yaml.dump(data, f, default_flow_style=False)
|
|
68
|
+
|
|
69
|
+
def create_benchmark_yaml(path: str, n: int) -> None:
|
|
70
|
+
"""Creates a Cloudmesh service YAML test file with specified number of services.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
path: Path where the benchmark YAML file should be created.
|
|
74
|
+
n: Number of services to include in the benchmark file.
|
|
75
|
+
|
|
76
|
+
"""
|
|
77
|
+
cm = {"cloudmesh": {}}
|
|
78
|
+
for i in range(0, n):
|
|
79
|
+
cm["cloudmesh"][f"service{i}"] = {"attribute": f"service{i}"}
|
|
80
|
+
|
|
81
|
+
location = path_expand(path)
|
|
82
|
+
with open(location, "w") as yaml_file:
|
|
83
|
+
yaml.dump(cm, yaml_file, default_flow_style=False)
|
|
84
|
+
|
|
85
|
+
def create_benchmark_file(path: str, n: int) -> int:
|
|
86
|
+
"""Creates a file of a given size in binary megabytes.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
path: Path where the benchmark file should be created.
|
|
90
|
+
n: Size of the file in megabytes.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
The actual size of the created file in megabytes.
|
|
94
|
+
"""
|
|
95
|
+
location = path_expand(path)
|
|
96
|
+
size = 1048576 * n # size in bytes
|
|
97
|
+
with open(location, "wb") as f:
|
|
98
|
+
f.write(os.urandom(size))
|
|
99
|
+
|
|
100
|
+
s = os.path.getsize(location)
|
|
101
|
+
return int(s / 1048576.0)
|