opensecureconf-client 2.0.2__tar.gz → 2.3.1__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.
- {opensecureconf_client-2.0.2/opensecureconf_client.egg-info → opensecureconf_client-2.3.1}/PKG-INFO +1 -1
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1/opensecureconf_client.egg-info}/PKG-INFO +1 -1
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/opensecureconf_client.py +124 -75
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/pyproject.toml +1 -1
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/ADVANCED_EXAMPLES.md +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/LICENSE +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/MANIFEST.in +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/README.md +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/example_enhanced_usage.py +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/example_usage.py +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/opensecureconf_client.egg-info/SOURCES.txt +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/opensecureconf_client.egg-info/dependency_links.txt +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/opensecureconf_client.egg-info/requires.txt +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/opensecureconf_client.egg-info/top_level.txt +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/setup.cfg +0 -0
- {opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1}/setup.py +0 -0
{opensecureconf_client-2.0.2/opensecureconf_client.egg-info → opensecureconf_client-2.3.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opensecureconf-client
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.1
|
|
4
4
|
Summary: Python client library for OpenSecureConf encrypted configuration management API with clustering support
|
|
5
5
|
Author-email: Alessandro Pioli <alessandro.pioli+apioli-pypi@gmail.com>
|
|
6
6
|
Maintainer-email: Alessandro Pioli <alessandro.pioli+apioli-pypi@gmail.com>
|
{opensecureconf_client-2.0.2 → opensecureconf_client-2.3.1/opensecureconf_client.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opensecureconf-client
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.1
|
|
4
4
|
Summary: Python client library for OpenSecureConf encrypted configuration management API with clustering support
|
|
5
5
|
Author-email: Alessandro Pioli <alessandro.pioli+apioli-pypi@gmail.com>
|
|
6
6
|
Maintainer-email: Alessandro Pioli <alessandro.pioli+apioli-pypi@gmail.com>
|
|
@@ -12,9 +12,11 @@ Enhanced Features:
|
|
|
12
12
|
- Batch operations
|
|
13
13
|
- Enhanced input validation
|
|
14
14
|
- Health check utilities
|
|
15
|
+
- Support for multiple value types (dict, str, int, bool, list)
|
|
16
|
+
- Category and environment support
|
|
15
17
|
"""
|
|
16
18
|
|
|
17
|
-
from typing import Any, Dict, List, Optional
|
|
19
|
+
from typing import Any, Dict, List, Optional, Union
|
|
18
20
|
import logging
|
|
19
21
|
import time
|
|
20
22
|
import requests
|
|
@@ -22,7 +24,6 @@ from requests.adapters import HTTPAdapter
|
|
|
22
24
|
from requests.exceptions import Timeout, RequestException
|
|
23
25
|
from urllib3.util.retry import Retry
|
|
24
26
|
|
|
25
|
-
|
|
26
27
|
# ============================================================================
|
|
27
28
|
# EXCEPTIONS
|
|
28
29
|
# ============================================================================
|
|
@@ -30,23 +31,18 @@ from urllib3.util.retry import Retry
|
|
|
30
31
|
class OpenSecureConfError(Exception):
|
|
31
32
|
"""Base exception for OpenSecureConf client errors."""
|
|
32
33
|
|
|
33
|
-
|
|
34
34
|
class AuthenticationError(OpenSecureConfError):
|
|
35
35
|
"""Raised when authentication fails (invalid or missing user key)."""
|
|
36
36
|
|
|
37
|
-
|
|
38
37
|
class ConfigurationNotFoundError(OpenSecureConfError):
|
|
39
38
|
"""Raised when a requested configuration key does not exist."""
|
|
40
39
|
|
|
41
|
-
|
|
42
40
|
class ConfigurationExistsError(OpenSecureConfError):
|
|
43
41
|
"""Raised when attempting to create a configuration that already exists."""
|
|
44
42
|
|
|
45
|
-
|
|
46
43
|
class ClusterError(OpenSecureConfError):
|
|
47
44
|
"""Raised when cluster operations fail."""
|
|
48
45
|
|
|
49
|
-
|
|
50
46
|
# ============================================================================
|
|
51
47
|
# CLIENT
|
|
52
48
|
# ============================================================================
|
|
@@ -73,9 +69,12 @@ class OpenSecureConfClient:
|
|
|
73
69
|
... enable_retry=True,
|
|
74
70
|
... log_level="INFO"
|
|
75
71
|
... )
|
|
76
|
-
>>>
|
|
77
|
-
>>>
|
|
78
|
-
|
|
72
|
+
>>> # Dict value with category and environment
|
|
73
|
+
>>> config = client.create("database", {"host": "localhost", "port": 5432},
|
|
74
|
+
... category="config", environment="production")
|
|
75
|
+
>>> # String value
|
|
76
|
+
>>> config = client.create("api_token", "secret-token-123",
|
|
77
|
+
... category="auth", environment="staging")
|
|
79
78
|
"""
|
|
80
79
|
|
|
81
80
|
def __init__(
|
|
@@ -171,12 +170,10 @@ class OpenSecureConfClient:
|
|
|
171
170
|
"x-user-key": self.user_key,
|
|
172
171
|
"Content-Type": "application/json"
|
|
173
172
|
}
|
|
174
|
-
|
|
175
173
|
if self.api_key:
|
|
176
174
|
headers["X-API-Key"] = self.api_key
|
|
177
175
|
|
|
178
176
|
self._session.headers.update(headers)
|
|
179
|
-
|
|
180
177
|
self.logger.info(f"Client initialized for {self.base_url}")
|
|
181
178
|
|
|
182
179
|
def _make_request(self, method: str, endpoint: str, **kwargs) -> Any:
|
|
@@ -208,7 +205,6 @@ class OpenSecureConfClient:
|
|
|
208
205
|
try:
|
|
209
206
|
response = self._session.request(method, url, **kwargs)
|
|
210
207
|
duration = time.time() - start_time
|
|
211
|
-
|
|
212
208
|
self.logger.info(
|
|
213
209
|
f"{method} {endpoint} - Status: {response.status_code} - Duration: {duration:.3f}s"
|
|
214
210
|
)
|
|
@@ -295,7 +291,7 @@ class OpenSecureConfClient:
|
|
|
295
291
|
Example:
|
|
296
292
|
>>> info = client.get_service_info()
|
|
297
293
|
>>> print(info["version"])
|
|
298
|
-
2.
|
|
294
|
+
2.2.0
|
|
299
295
|
"""
|
|
300
296
|
return self._make_request("GET", "/")
|
|
301
297
|
|
|
@@ -350,18 +346,20 @@ class OpenSecureConfClient:
|
|
|
350
346
|
# ========================================================================
|
|
351
347
|
|
|
352
348
|
def create(
|
|
353
|
-
self,
|
|
354
|
-
key: str,
|
|
355
|
-
value: Dict[str, Any],
|
|
356
|
-
category: Optional[str] = None
|
|
349
|
+
self,
|
|
350
|
+
key: str,
|
|
351
|
+
value: Union[Dict[str, Any], str, int, bool, list],
|
|
352
|
+
category: Optional[str] = None,
|
|
353
|
+
environment: Optional[str] = None
|
|
357
354
|
) -> Dict[str, Any]:
|
|
358
355
|
"""
|
|
359
356
|
Create a new encrypted configuration entry.
|
|
360
357
|
|
|
361
358
|
Args:
|
|
362
359
|
key: Unique configuration key (1-255 characters)
|
|
363
|
-
value: Configuration data
|
|
360
|
+
value: Configuration data (dict, string, int, bool, or list - will be encrypted)
|
|
364
361
|
category: Optional category for grouping (max 100 characters)
|
|
362
|
+
environment: Optional environment identifier (max 100 characters)
|
|
365
363
|
|
|
366
364
|
Returns:
|
|
367
365
|
Dictionary containing the created configuration with fields:
|
|
@@ -369,29 +367,35 @@ class OpenSecureConfClient:
|
|
|
369
367
|
- key: Configuration key
|
|
370
368
|
- value: Configuration value (decrypted)
|
|
371
369
|
- category: Configuration category (if set)
|
|
370
|
+
- environment: Environment identifier (if set)
|
|
372
371
|
|
|
373
372
|
Raises:
|
|
374
373
|
ConfigurationExistsError: If configuration key already exists
|
|
375
|
-
ValueError: If key
|
|
374
|
+
ValueError: If key is invalid
|
|
376
375
|
|
|
377
376
|
Example:
|
|
378
|
-
>>>
|
|
379
|
-
|
|
380
|
-
...
|
|
381
|
-
|
|
382
|
-
|
|
377
|
+
>>> # Dict value with category and environment
|
|
378
|
+
>>> config = client.create("database", {"host": "localhost", "port": 5432},
|
|
379
|
+
... category="config", environment="production")
|
|
380
|
+
>>> # String value
|
|
381
|
+
>>> config = client.create("api_token", "secret-123",
|
|
382
|
+
... category="auth", environment="staging")
|
|
383
|
+
>>> # Integer value
|
|
384
|
+
>>> config = client.create("max_retries", 3, environment="production")
|
|
385
|
+
>>> # Boolean value
|
|
386
|
+
>>> config = client.create("debug", False, category="settings", environment="dev")
|
|
383
387
|
"""
|
|
384
388
|
# Enhanced validation
|
|
385
389
|
if not key or not isinstance(key, str):
|
|
386
390
|
raise ValueError("Key must be a non-empty string")
|
|
387
391
|
if len(key) > 255:
|
|
388
392
|
raise ValueError("Key must be between 1 and 255 characters")
|
|
389
|
-
if not isinstance(value, dict):
|
|
390
|
-
raise ValueError("Value must be a dictionary")
|
|
391
393
|
if category and len(category) > 100:
|
|
392
394
|
raise ValueError("Category must be max 100 characters")
|
|
395
|
+
if environment and len(environment) > 100:
|
|
396
|
+
raise ValueError("Environment must be max 100 characters")
|
|
393
397
|
|
|
394
|
-
payload = {"key": key, "value": value, "category": category}
|
|
398
|
+
payload = {"key": key, "value": value, "category": category, "environment": environment}
|
|
395
399
|
return self._make_request("POST", "/configs", json=payload)
|
|
396
400
|
|
|
397
401
|
def read(self, key: str) -> Dict[str, Any]:
|
|
@@ -403,6 +407,7 @@ class OpenSecureConfClient:
|
|
|
403
407
|
|
|
404
408
|
Returns:
|
|
405
409
|
Dictionary containing the configuration with decrypted value
|
|
410
|
+
The value can be dict, str, int, bool, or list depending on what was stored
|
|
406
411
|
|
|
407
412
|
Raises:
|
|
408
413
|
ConfigurationNotFoundError: If configuration key does not exist
|
|
@@ -410,8 +415,8 @@ class OpenSecureConfClient:
|
|
|
410
415
|
|
|
411
416
|
Example:
|
|
412
417
|
>>> config = client.read("database")
|
|
413
|
-
>>> print(config["value"]
|
|
414
|
-
|
|
418
|
+
>>> print(config["value"]) # Could be any supported type
|
|
419
|
+
>>> print(config["environment"]) # e.g., "production"
|
|
415
420
|
"""
|
|
416
421
|
if not key or not isinstance(key, str):
|
|
417
422
|
raise ValueError("Key must be a non-empty string")
|
|
@@ -419,40 +424,43 @@ class OpenSecureConfClient:
|
|
|
419
424
|
return self._make_request("GET", f"/configs/{key}")
|
|
420
425
|
|
|
421
426
|
def update(
|
|
422
|
-
self,
|
|
423
|
-
key: str,
|
|
424
|
-
value: Dict[str, Any],
|
|
425
|
-
category: Optional[str] = None
|
|
427
|
+
self,
|
|
428
|
+
key: str,
|
|
429
|
+
value: Union[Dict[str, Any], str, int, bool, list],
|
|
430
|
+
category: Optional[str] = None,
|
|
431
|
+
environment: Optional[str] = None
|
|
426
432
|
) -> Dict[str, Any]:
|
|
427
433
|
"""
|
|
428
434
|
Update an existing configuration entry with new encrypted value.
|
|
429
435
|
|
|
430
436
|
Args:
|
|
431
437
|
key: Configuration key to update
|
|
432
|
-
value: New configuration data
|
|
438
|
+
value: New configuration data (dict, string, int, bool, or list - will be encrypted)
|
|
433
439
|
category: Optional new category
|
|
440
|
+
environment: Optional new environment
|
|
434
441
|
|
|
435
442
|
Returns:
|
|
436
443
|
Dictionary containing the updated configuration with decrypted value
|
|
437
444
|
|
|
438
445
|
Raises:
|
|
439
446
|
ConfigurationNotFoundError: If configuration key does not exist
|
|
440
|
-
ValueError: If
|
|
447
|
+
ValueError: If key is invalid
|
|
441
448
|
|
|
442
449
|
Example:
|
|
443
|
-
>>>
|
|
444
|
-
|
|
445
|
-
...
|
|
446
|
-
|
|
450
|
+
>>> # Update with dict
|
|
451
|
+
>>> config = client.update("database", {"host": "db.example.com", "port": 5432},
|
|
452
|
+
... environment="production")
|
|
453
|
+
>>> # Update with string and change environment
|
|
454
|
+
>>> config = client.update("api_token", "new-token-456", environment="staging")
|
|
447
455
|
"""
|
|
448
456
|
if not key or not isinstance(key, str):
|
|
449
457
|
raise ValueError("Key must be a non-empty string")
|
|
450
|
-
if not isinstance(value, dict):
|
|
451
|
-
raise ValueError("Value must be a dictionary")
|
|
452
458
|
if category and len(category) > 100:
|
|
453
459
|
raise ValueError("Category must be max 100 characters")
|
|
460
|
+
if environment and len(environment) > 100:
|
|
461
|
+
raise ValueError("Environment must be max 100 characters")
|
|
454
462
|
|
|
455
|
-
payload = {"value": value, "category": category}
|
|
463
|
+
payload = {"value": value, "category": category, "environment": environment}
|
|
456
464
|
return self._make_request("PUT", f"/configs/{key}", json=payload)
|
|
457
465
|
|
|
458
466
|
def delete(self, key: str) -> Dict[str, str]:
|
|
@@ -479,23 +487,35 @@ class OpenSecureConfClient:
|
|
|
479
487
|
|
|
480
488
|
return self._make_request("DELETE", f"/configs/{key}")
|
|
481
489
|
|
|
482
|
-
def list_all(self, category: Optional[str] = None) -> List[Dict[str, Any]]:
|
|
490
|
+
def list_all(self, category: Optional[str] = None, environment: Optional[str] = None) -> List[Dict[str, Any]]:
|
|
483
491
|
"""
|
|
484
|
-
List all configurations with optional category
|
|
492
|
+
List all configurations with optional category and environment filters.
|
|
485
493
|
All values are automatically decrypted.
|
|
486
494
|
|
|
487
495
|
Args:
|
|
488
496
|
category: Optional filter by category
|
|
497
|
+
environment: Optional filter by environment
|
|
489
498
|
|
|
490
499
|
Returns:
|
|
491
500
|
List of configuration dictionaries with decrypted values
|
|
501
|
+
Each value can be dict, str, int, bool, or list
|
|
492
502
|
|
|
493
503
|
Example:
|
|
494
|
-
>>>
|
|
495
|
-
>>>
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
504
|
+
>>> # List all
|
|
505
|
+
>>> configs = client.list_all()
|
|
506
|
+
>>> # Filter by category
|
|
507
|
+
>>> prod_configs = client.list_all(category="production")
|
|
508
|
+
>>> # Filter by environment
|
|
509
|
+
>>> staging_configs = client.list_all(environment="staging")
|
|
510
|
+
>>> # Filter by both
|
|
511
|
+
>>> configs = client.list_all(category="database", environment="production")
|
|
512
|
+
"""
|
|
513
|
+
params = {}
|
|
514
|
+
if category:
|
|
515
|
+
params["category"] = category
|
|
516
|
+
if environment:
|
|
517
|
+
params["environment"] = environment
|
|
518
|
+
|
|
499
519
|
return self._make_request("GET", "/configs", params=params)
|
|
500
520
|
|
|
501
521
|
# ========================================================================
|
|
@@ -503,15 +523,17 @@ class OpenSecureConfClient:
|
|
|
503
523
|
# ========================================================================
|
|
504
524
|
|
|
505
525
|
def bulk_create(
|
|
506
|
-
self,
|
|
507
|
-
configs: List[Dict[str, Any]],
|
|
526
|
+
self,
|
|
527
|
+
configs: List[Dict[str, Any]],
|
|
508
528
|
ignore_errors: bool = False
|
|
509
529
|
) -> List[Dict[str, Any]]:
|
|
510
530
|
"""
|
|
511
531
|
Create multiple configurations in batch.
|
|
512
532
|
|
|
513
533
|
Args:
|
|
514
|
-
configs: List of configuration dictionaries with 'key', 'value',
|
|
534
|
+
configs: List of configuration dictionaries with 'key', 'value',
|
|
535
|
+
and optional 'category' and 'environment'
|
|
536
|
+
Value can be dict, str, int, bool, or list
|
|
515
537
|
ignore_errors: If True, continue on errors and return partial results
|
|
516
538
|
|
|
517
539
|
Returns:
|
|
@@ -523,8 +545,12 @@ class OpenSecureConfClient:
|
|
|
523
545
|
|
|
524
546
|
Example:
|
|
525
547
|
>>> configs = [
|
|
526
|
-
... {"key": "db1", "value": {"host": "localhost"},
|
|
527
|
-
...
|
|
548
|
+
... {"key": "db1", "value": {"host": "localhost"},
|
|
549
|
+
... "category": "db", "environment": "production"},
|
|
550
|
+
... {"key": "token", "value": "secret-123",
|
|
551
|
+
... "category": "auth", "environment": "staging"},
|
|
552
|
+
... {"key": "retries", "value": 3,
|
|
553
|
+
... "category": "config", "environment": "production"}
|
|
528
554
|
... ]
|
|
529
555
|
>>> results = client.bulk_create(configs)
|
|
530
556
|
>>> print(f"Created {len(results)} configurations")
|
|
@@ -545,7 +571,8 @@ class OpenSecureConfClient:
|
|
|
545
571
|
result = self.create(
|
|
546
572
|
key=config["key"],
|
|
547
573
|
value=config["value"],
|
|
548
|
-
category=config.get("category")
|
|
574
|
+
category=config.get("category"),
|
|
575
|
+
environment=config.get("environment")
|
|
549
576
|
)
|
|
550
577
|
results.append(result)
|
|
551
578
|
self.logger.info(f"Bulk create: created '{config['key']}'")
|
|
@@ -562,8 +589,8 @@ class OpenSecureConfClient:
|
|
|
562
589
|
return results
|
|
563
590
|
|
|
564
591
|
def bulk_read(
|
|
565
|
-
self,
|
|
566
|
-
keys: List[str],
|
|
592
|
+
self,
|
|
593
|
+
keys: List[str],
|
|
567
594
|
ignore_errors: bool = False
|
|
568
595
|
) -> List[Dict[str, Any]]:
|
|
569
596
|
"""
|
|
@@ -577,7 +604,7 @@ class OpenSecureConfClient:
|
|
|
577
604
|
List of configuration dictionaries
|
|
578
605
|
|
|
579
606
|
Example:
|
|
580
|
-
>>> configs = client.bulk_read(["db1", "
|
|
607
|
+
>>> configs = client.bulk_read(["db1", "token", "retries"])
|
|
581
608
|
>>> print(f"Retrieved {len(configs)} configurations")
|
|
582
609
|
"""
|
|
583
610
|
if not isinstance(keys, list):
|
|
@@ -604,8 +631,8 @@ class OpenSecureConfClient:
|
|
|
604
631
|
return results
|
|
605
632
|
|
|
606
633
|
def bulk_delete(
|
|
607
|
-
self,
|
|
608
|
-
keys: List[str],
|
|
634
|
+
self,
|
|
635
|
+
keys: List[str],
|
|
609
636
|
ignore_errors: bool = False
|
|
610
637
|
) -> Dict[str, Any]:
|
|
611
638
|
"""
|
|
@@ -666,46 +693,48 @@ class OpenSecureConfClient:
|
|
|
666
693
|
return False
|
|
667
694
|
|
|
668
695
|
def get_or_default(
|
|
669
|
-
self,
|
|
670
|
-
key: str,
|
|
671
|
-
default: Dict[str, Any]
|
|
696
|
+
self,
|
|
697
|
+
key: str,
|
|
698
|
+
default: Union[Dict[str, Any], str, int, bool, list]
|
|
672
699
|
) -> Dict[str, Any]:
|
|
673
700
|
"""
|
|
674
701
|
Get configuration value or return default if not found.
|
|
675
702
|
|
|
676
703
|
Args:
|
|
677
704
|
key: Configuration key to retrieve
|
|
678
|
-
default: Default value to return if key not found
|
|
705
|
+
default: Default value to return if key not found (any supported type)
|
|
679
706
|
|
|
680
707
|
Returns:
|
|
681
|
-
Configuration dictionary or default value
|
|
708
|
+
Configuration dictionary or default value wrapped in dict format
|
|
682
709
|
|
|
683
710
|
Example:
|
|
684
|
-
>>>
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
711
|
+
>>> # Dict default
|
|
712
|
+
>>> config = client.get_or_default("database", {"host": "localhost", "port": 5432})
|
|
713
|
+
>>> # String default
|
|
714
|
+
>>> config = client.get_or_default("token", "default-token")
|
|
688
715
|
"""
|
|
689
716
|
try:
|
|
690
717
|
return self.read(key)
|
|
691
718
|
except ConfigurationNotFoundError:
|
|
692
|
-
return {"key": key, "value": default, "category": None}
|
|
719
|
+
return {"key": key, "value": default, "category": None, "environment": None}
|
|
693
720
|
|
|
694
|
-
def count(self, category: Optional[str] = None) -> int:
|
|
721
|
+
def count(self, category: Optional[str] = None, environment: Optional[str] = None) -> int:
|
|
695
722
|
"""
|
|
696
|
-
Count total configurations, optionally filtered by category.
|
|
723
|
+
Count total configurations, optionally filtered by category and/or environment.
|
|
697
724
|
|
|
698
725
|
Args:
|
|
699
726
|
category: Optional category filter
|
|
727
|
+
environment: Optional environment filter
|
|
700
728
|
|
|
701
729
|
Returns:
|
|
702
730
|
Number of configurations
|
|
703
731
|
|
|
704
732
|
Example:
|
|
705
733
|
>>> total = client.count()
|
|
706
|
-
>>> prod_count = client.count(
|
|
734
|
+
>>> prod_count = client.count(environment="production")
|
|
735
|
+
>>> db_prod_count = client.count(category="database", environment="production")
|
|
707
736
|
"""
|
|
708
|
-
configs = self.list_all(category=category)
|
|
737
|
+
configs = self.list_all(category=category, environment=environment)
|
|
709
738
|
return len(configs)
|
|
710
739
|
|
|
711
740
|
def list_categories(self) -> List[str]:
|
|
@@ -727,6 +756,26 @@ class OpenSecureConfClient:
|
|
|
727
756
|
categories.add(cat)
|
|
728
757
|
return sorted(list(categories))
|
|
729
758
|
|
|
759
|
+
def list_environments(self) -> List[str]:
|
|
760
|
+
"""
|
|
761
|
+
Get list of all unique environments.
|
|
762
|
+
|
|
763
|
+
Returns:
|
|
764
|
+
List of environment names
|
|
765
|
+
|
|
766
|
+
Example:
|
|
767
|
+
>>> environments = client.list_environments()
|
|
768
|
+
>>> print(f"Environments: {', '.join(environments)}")
|
|
769
|
+
Environments: production, staging, development
|
|
770
|
+
"""
|
|
771
|
+
configs = self.list_all()
|
|
772
|
+
environments = set()
|
|
773
|
+
for config in configs:
|
|
774
|
+
env = config.get("environment")
|
|
775
|
+
if env:
|
|
776
|
+
environments.add(env)
|
|
777
|
+
return sorted(list(environments))
|
|
778
|
+
|
|
730
779
|
# ========================================================================
|
|
731
780
|
# SESSION MANAGEMENT
|
|
732
781
|
# ========================================================================
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "opensecureconf-client"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.3.1"
|
|
8
8
|
description = "Python client library for OpenSecureConf encrypted configuration management API with clustering support"
|
|
9
9
|
readme = "README.md" # Updated to use the complete README
|
|
10
10
|
requires-python = ">=3.8"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|