dmtri 0.1.0__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.
dmtri-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,174 @@
1
+ Metadata-Version: 2.4
2
+ Name: dmtri
3
+ Version: 0.1.0
4
+ Summary: CLI tool for triggering datacenter metadata updates
5
+ Author-email: Nikos Sokos <nsokos@noa.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: ansible>=6.7.0
9
+ Requires-Dist: ansible-runner>=2.3.6
10
+ Requires-Dist: appdirs>=1.4.4
11
+ Requires-Dist: pytest>=8.3.5
12
+ Requires-Dist: pytest-cov>=5.0.0
13
+ Requires-Dist: requests
14
+ Requires-Dist: tomli>=2.2.1
15
+
16
+ # dmtri
17
+
18
+ [![Run Tests](https://github.com/EIDA/dmtri/actions/workflows/pytest.yml/badge.svg)](https://github.com/EIDA/dmtri/actions/workflows/pytest.yml)
19
+ ![Coverage](badges/coverage.svg)
20
+
21
+ `dmtri` is a command-line tool designed to trigger metadata and data refresh simulations across EIDA nodes using Ansible automation.
22
+
23
+ ---
24
+ - `seedpsd`
25
+ - `wfcatalog`
26
+ - `availability`
27
+
28
+ It uses `.dmtri_jobs.json` per host to track async job state and integrates with `uv` and `ansible` for CLI automation.
29
+
30
+ ---
31
+
32
+ ## Quick Start
33
+
34
+ You can use `dmtri` in two ways, depending on your preference:
35
+
36
+ ### Option 1: Using `uvx`
37
+
38
+ You can run commands using:
39
+
40
+ ```bash
41
+ uvx dmtri <command> [options]
42
+
43
+ ```
44
+
45
+ ---
46
+
47
+ ### Option 2: Global (Tool-based) — Ideal for global CLI use
48
+
49
+ ```bash
50
+ uv tool install dmtri
51
+ ```
52
+
53
+ This makes `dmtri` available globally:
54
+
55
+ ```bash
56
+ dmtri <command> [options]
57
+
58
+ ```
59
+
60
+ You can update it any time using:
61
+
62
+ ```bash
63
+ uv tool upgrade dmtri
64
+ ```
65
+
66
+ ---
67
+
68
+ ### 2. Configure inventory
69
+
70
+ Edit the file: `src/inventory/hosts.ini`
71
+
72
+ Example:
73
+
74
+ ```ini
75
+ [seedpsd_nodes]
76
+ <SEEDPSD_HOST> ansible_user=<USER> ansible_ssh_pass="<PASSWORD>" ansible_connection=ssh ansible_become=false ansible_ssh_common_args='-o StrictHostKeyChecking=no'
77
+
78
+ [seedpsd_nodes:vars]
79
+ seedpsd_dir=/home/<USER>/seedpsd
80
+
81
+ [wf_catalogue]
82
+ <WFCATALOG_HOST> ansible_user=<USER> ansible_ssh_pass="<PASSWORD>" ansible_connection=ssh ansible_become=false ansible_ssh_common_args='-o StrictHostKeyChecking=no'
83
+
84
+ [wf_catalogue:vars]
85
+ collector_dir=/home/<USER>/Programs/wfcatalogue<VERSION>/wfcatalog/collector2
86
+
87
+ [ws_availability]
88
+ <AVAILABILITY_HOST> ansible_user=<USER> ansible_ssh_pass="<PASSWORD>" ansible_connection=ssh ansible_become=false ansible_ssh_common_args='-o StrictHostKeyChecking=no'
89
+
90
+ [ws_availability:vars]
91
+ availability_dir=/home/<USER>/Programs/ws-availability<VERSION>/views
92
+ mongo_user=<MONGO_USERNAME>
93
+ mongo_pass=<MONGO_PASSWORD>
94
+ mongo_authdb=<MONGO_DATABASE>
95
+
96
+ ```
97
+
98
+ ---
99
+
100
+ ### 3. Run example jobs
101
+
102
+ By default, this command runs **all refresh playbooks** (seedpsd, wfcatalog, and availability):
103
+
104
+ ```bash
105
+ uv run dmtri refresh -e "network=HL station=ATH starttime=2024-01-01T00:00:00 endtime=2024-01-02T00:00:00"
106
+ ```
107
+
108
+ ---
109
+
110
+ ### 4. Track jobs across hosts
111
+
112
+ ```bash
113
+ uv run dmtri track
114
+ ```
115
+
116
+ Shows per-host job status:
117
+ ```
118
+ Job ID: j123... Type: seedpsd Station: ATH Status: ✅ Finished
119
+ Job ID: manual-... Type: availability Status: ✅ Manual (not tracked)
120
+ ```
121
+
122
+ ---
123
+
124
+ ### 5. Troubleshooting with `dmtri doctor`
125
+
126
+ Check SSH connectivity to your configured hosts using:
127
+
128
+ ```bash
129
+ uv run dmtri doctor
130
+ ```
131
+
132
+ This uses the Ansible `ping` module to test access to all servers in your inventory.
133
+
134
+ #### Options
135
+
136
+ - `--verbose` — Show full output from each host
137
+
138
+ #### Example
139
+
140
+ ```bash
141
+ uv run dmtri doctor --verbose
142
+ ```
143
+
144
+ If no response is received, ensure:
145
+
146
+ - You're connected to the VPN (if applicable)
147
+ - SSH access is configured correctly in your inventory file
148
+ - Host IPs and credentials are reachable and valid
149
+
150
+ ### Operation Details
151
+
152
+ `dmtri` supports two main operations for both metadata and data: `refresh` and `clean`. These affect the following components:
153
+
154
+ #### 🔄 Refresh
155
+
156
+ - **Metadata**
157
+ - `seedpsd`: Scans for new metadata.
158
+ - `availability`: Refreshes the view in MongoDB.
159
+
160
+ - **Data**
161
+ - Identifies data files in the archive for the specified epoch (by NSLC and time range).
162
+ - `seedpsd`: Recalculates seedPSD for new files.
163
+ - `wfcatalog`: Runs the collector on new data files.
164
+
165
+ #### 🧹 Clean
166
+
167
+ - **Metadata**
168
+ - `seedpsd`: Removes the metadata entries.
169
+ - `availability`: Refreshes the view in MongoDB.
170
+
171
+ - **Data**
172
+ - Identifies data files in the archive for the specified epoch.
173
+ - `seedpsd`: Removes associated seedPSD data (via CLI).
174
+ - `wfcatalog`: Removes files using the `--delete` option in the collector.
dmtri-0.1.0/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # dmtri
2
+
3
+ [![Run Tests](https://github.com/EIDA/dmtri/actions/workflows/pytest.yml/badge.svg)](https://github.com/EIDA/dmtri/actions/workflows/pytest.yml)
4
+ ![Coverage](badges/coverage.svg)
5
+
6
+ `dmtri` is a command-line tool designed to trigger metadata and data refresh simulations across EIDA nodes using Ansible automation.
7
+
8
+ ---
9
+ - `seedpsd`
10
+ - `wfcatalog`
11
+ - `availability`
12
+
13
+ It uses `.dmtri_jobs.json` per host to track async job state and integrates with `uv` and `ansible` for CLI automation.
14
+
15
+ ---
16
+
17
+ ## Quick Start
18
+
19
+ You can use `dmtri` in two ways, depending on your preference:
20
+
21
+ ### Option 1: Using `uvx`
22
+
23
+ You can run commands using:
24
+
25
+ ```bash
26
+ uvx dmtri <command> [options]
27
+
28
+ ```
29
+
30
+ ---
31
+
32
+ ### Option 2: Global (Tool-based) — Ideal for global CLI use
33
+
34
+ ```bash
35
+ uv tool install dmtri
36
+ ```
37
+
38
+ This makes `dmtri` available globally:
39
+
40
+ ```bash
41
+ dmtri <command> [options]
42
+
43
+ ```
44
+
45
+ You can update it any time using:
46
+
47
+ ```bash
48
+ uv tool upgrade dmtri
49
+ ```
50
+
51
+ ---
52
+
53
+ ### 2. Configure inventory
54
+
55
+ Edit the file: `src/inventory/hosts.ini`
56
+
57
+ Example:
58
+
59
+ ```ini
60
+ [seedpsd_nodes]
61
+ <SEEDPSD_HOST> ansible_user=<USER> ansible_ssh_pass="<PASSWORD>" ansible_connection=ssh ansible_become=false ansible_ssh_common_args='-o StrictHostKeyChecking=no'
62
+
63
+ [seedpsd_nodes:vars]
64
+ seedpsd_dir=/home/<USER>/seedpsd
65
+
66
+ [wf_catalogue]
67
+ <WFCATALOG_HOST> ansible_user=<USER> ansible_ssh_pass="<PASSWORD>" ansible_connection=ssh ansible_become=false ansible_ssh_common_args='-o StrictHostKeyChecking=no'
68
+
69
+ [wf_catalogue:vars]
70
+ collector_dir=/home/<USER>/Programs/wfcatalogue<VERSION>/wfcatalog/collector2
71
+
72
+ [ws_availability]
73
+ <AVAILABILITY_HOST> ansible_user=<USER> ansible_ssh_pass="<PASSWORD>" ansible_connection=ssh ansible_become=false ansible_ssh_common_args='-o StrictHostKeyChecking=no'
74
+
75
+ [ws_availability:vars]
76
+ availability_dir=/home/<USER>/Programs/ws-availability<VERSION>/views
77
+ mongo_user=<MONGO_USERNAME>
78
+ mongo_pass=<MONGO_PASSWORD>
79
+ mongo_authdb=<MONGO_DATABASE>
80
+
81
+ ```
82
+
83
+ ---
84
+
85
+ ### 3. Run example jobs
86
+
87
+ By default, this command runs **all refresh playbooks** (seedpsd, wfcatalog, and availability):
88
+
89
+ ```bash
90
+ uv run dmtri refresh -e "network=HL station=ATH starttime=2024-01-01T00:00:00 endtime=2024-01-02T00:00:00"
91
+ ```
92
+
93
+ ---
94
+
95
+ ### 4. Track jobs across hosts
96
+
97
+ ```bash
98
+ uv run dmtri track
99
+ ```
100
+
101
+ Shows per-host job status:
102
+ ```
103
+ Job ID: j123... Type: seedpsd Station: ATH Status: ✅ Finished
104
+ Job ID: manual-... Type: availability Status: ✅ Manual (not tracked)
105
+ ```
106
+
107
+ ---
108
+
109
+ ### 5. Troubleshooting with `dmtri doctor`
110
+
111
+ Check SSH connectivity to your configured hosts using:
112
+
113
+ ```bash
114
+ uv run dmtri doctor
115
+ ```
116
+
117
+ This uses the Ansible `ping` module to test access to all servers in your inventory.
118
+
119
+ #### Options
120
+
121
+ - `--verbose` — Show full output from each host
122
+
123
+ #### Example
124
+
125
+ ```bash
126
+ uv run dmtri doctor --verbose
127
+ ```
128
+
129
+ If no response is received, ensure:
130
+
131
+ - You're connected to the VPN (if applicable)
132
+ - SSH access is configured correctly in your inventory file
133
+ - Host IPs and credentials are reachable and valid
134
+
135
+ ### Operation Details
136
+
137
+ `dmtri` supports two main operations for both metadata and data: `refresh` and `clean`. These affect the following components:
138
+
139
+ #### 🔄 Refresh
140
+
141
+ - **Metadata**
142
+ - `seedpsd`: Scans for new metadata.
143
+ - `availability`: Refreshes the view in MongoDB.
144
+
145
+ - **Data**
146
+ - Identifies data files in the archive for the specified epoch (by NSLC and time range).
147
+ - `seedpsd`: Recalculates seedPSD for new files.
148
+ - `wfcatalog`: Runs the collector on new data files.
149
+
150
+ #### 🧹 Clean
151
+
152
+ - **Metadata**
153
+ - `seedpsd`: Removes the metadata entries.
154
+ - `availability`: Refreshes the view in MongoDB.
155
+
156
+ - **Data**
157
+ - Identifies data files in the archive for the specified epoch.
158
+ - `seedpsd`: Removes associated seedPSD data (via CLI).
159
+ - `wfcatalog`: Removes files using the `--delete` option in the collector.
@@ -0,0 +1,28 @@
1
+ [project]
2
+ name = "dmtri"
3
+ version = "0.1.0"
4
+ description = "CLI tool for triggering datacenter metadata updates"
5
+ authors = [{ name = "Nikos Sokos", email = "nsokos@noa.com" }]
6
+ dependencies = [
7
+ "ansible>=6.7.0",
8
+ "ansible-runner>=2.3.6",
9
+ "appdirs>=1.4.4",
10
+ "pytest>=8.3.5",
11
+ "pytest-cov>=5.0.0",
12
+ "requests",
13
+ "tomli>=2.2.1",
14
+ ]
15
+ readme = "README.md"
16
+ requires-python = ">=3.8"
17
+ [tool.uv]
18
+ dev-dependencies = [
19
+ "pytest",
20
+ "pytest-cov"
21
+ ]
22
+
23
+
24
+ [project.scripts]
25
+ dmtri = "dmtri.cli:main"
26
+ [build-system]
27
+ requires = ["setuptools>=62.0", "wheel"]
28
+ build-backend = "setuptools.build_meta"
dmtri-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,118 @@
1
+ import argparse
2
+ import sys
3
+ import os
4
+ from datetime import datetime, timezone
5
+ import logging
6
+
7
+ from dmtri.execution_plan import print_execution_plan
8
+ from dmtri.utils import get_version, validate_and_normalize_args
9
+ from dmtri.hooks.hooks import run_hook
10
+ from dmtri.paths import COMMAND_PLAYBOOKS
11
+
12
+ logging.basicConfig(level=logging.INFO, format="%(message)s")
13
+ logger = logging.getLogger(__name__)
14
+
15
+ PROJECT_URL = "https://github.com/EIDA/dmtri/issues"
16
+
17
+ def main():
18
+ global_options = argparse.ArgumentParser(add_help=False)
19
+
20
+ parser = argparse.ArgumentParser(
21
+ description="Trigger data/metadata refresh or cleaning for multiple EIDA endpoints.",
22
+ parents=[global_options]
23
+ )
24
+ parser.add_argument(
25
+ "--version",
26
+ action="version",
27
+ version=f"%(prog)s version {get_version()} — See {PROJECT_URL} for updates or to report issues."
28
+ )
29
+
30
+ subparsers = parser.add_subparsers(dest="command")
31
+
32
+ shared = argparse.ArgumentParser(add_help=False, parents=[global_options])
33
+ shared.add_argument("-n", "--network", nargs="+", default=["*"], help="FDSN network code(s), supports wildcards")
34
+ shared.add_argument("-s", "--station", nargs="+", default=["*"], help="FDSN station code(s), supports wildcards")
35
+ shared.add_argument("-l", "--location", nargs="+", default=["*"], help="FDSN location code(s), supports wildcards")
36
+ shared.add_argument("-c", "--channel", nargs="+", default=["*"], help="FDSN channel code(s), supports wildcards")
37
+ shared.add_argument("-S", "--starttime", required=True, help="Start time (ISO 8601 format)")
38
+
39
+ now_str = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S")
40
+ shared.add_argument("-E", "--endtime", default=now_str, help="End time (default: now in UTC)")
41
+ shared.add_argument("--type", default="data,metadata", help="Comma-separated types to process (data, metadata)")
42
+ shared.add_argument("--no-confirm", action="store_true", help="Skip confirmation prompt before executing")
43
+ shared.add_argument("--debug", action="store_true", help="Show verbose output from Ansible")
44
+
45
+ subparsers.add_parser("refresh", parents=[shared], help="Refresh data/metadata using configured playbooks.")
46
+ subparsers.add_parser("clean", parents=[shared], help="Clean outdated data/metadata using configured playbooks.")
47
+ subparsers.add_parser("track", help="Track job status via tracking playbook.")
48
+ doctor_parser = subparsers.add_parser("doctor", help="Check SSH connectivity to all inventory hosts")
49
+ doctor_parser.add_argument("-v", "--verbose", action="store_true", help="Show full Ansible output per host")
50
+
51
+ args = parser.parse_args()
52
+ if args.command == "track":
53
+ cfg_file = "ansible_verbose.cfg"
54
+ else:
55
+ cfg_file = "ansible_verbose.cfg" if getattr(args, "debug", False) else "ansible_quiet.cfg"
56
+
57
+ cfg_path = os.path.abspath(cfg_file)
58
+ os.environ["ANSIBLE_CONFIG"] = cfg_path
59
+
60
+ if args.command == "doctor":
61
+ from dmtri.doctor import run_diagnostics
62
+ return run_diagnostics(verbose=args.verbose)
63
+
64
+ elif args.command in ("refresh", "clean"):
65
+ start_dt, end_dt, types = validate_and_normalize_args(args, parser)
66
+
67
+ vars_to_pass = {
68
+ "network": args.network,
69
+ "station": args.station,
70
+ "location": args.location,
71
+ "channel": args.channel,
72
+ "starttime": args.starttime,
73
+ "endtime": args.endtime,
74
+ "type": [t.strip() for t in args.type.split(",")],
75
+ "debug": args.debug,
76
+ }
77
+
78
+ if args.command == "refresh":
79
+ selected_types = vars_to_pass["type"]
80
+ valid_types = set(COMMAND_PLAYBOOKS["refresh"].keys())
81
+
82
+ invalid = set(selected_types) - valid_types
83
+ if invalid:
84
+ print(f" Invalid --type: {', '.join(invalid)}. Valid types are: {', '.join(valid_types)}.")
85
+ sys.exit(1)
86
+
87
+ playbooks = []
88
+ for t in selected_types:
89
+ playbooks.extend(COMMAND_PLAYBOOKS["refresh"][t])
90
+ else:
91
+ playbooks = COMMAND_PLAYBOOKS.get("clean", [])
92
+
93
+ if not playbooks:
94
+ print(f"No playbooks configured for command '{args.command}'.")
95
+ sys.exit(1)
96
+
97
+ if not args.no_confirm:
98
+ for pb in playbooks:
99
+ print_execution_plan(args.command, vars_to_pass, pb)
100
+ proceed = input("\nDo you want to proceed with executing all playbooks? (y/N): ").strip().lower()
101
+ if proceed != "y":
102
+ print("Aborted by user.")
103
+ sys.exit(0)
104
+
105
+ for pb in playbooks:
106
+ run_hook(pb, vars_to_pass)
107
+
108
+ elif args.command == "track":
109
+ playbooks = COMMAND_PLAYBOOKS.get("track", [])
110
+ if not playbooks:
111
+ print("No playbooks configured for command 'track'.")
112
+ sys.exit(1)
113
+ for pb in playbooks:
114
+ run_hook(pb, {})
115
+
116
+ else:
117
+ parser.print_help()
118
+ sys.exit(1)
@@ -0,0 +1,52 @@
1
+ import logging
2
+ import ansible_runner
3
+ from dmtri.paths import INVENTORY_FILE
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ def run_diagnostics(verbose=False, retries=1):
8
+ logger.info(f"Running connectivity check using inventory: {INVENTORY_FILE}")
9
+
10
+ ok_hosts = set()
11
+ unreachable_hosts = set()
12
+
13
+ for attempt in range(retries):
14
+ logger.info(f"Attempt {attempt + 1} of {retries}")
15
+
16
+ r = ansible_runner.run(
17
+ private_data_dir=".",
18
+ inventory=str(INVENTORY_FILE.resolve()),
19
+ module="ping",
20
+ host_pattern="all",
21
+ quiet=not verbose,
22
+ envvars={
23
+ "ANSIBLE_CACHE_PLUGIN": "memory" # Disable caching to avoid plugin warnings
24
+ }
25
+ )
26
+
27
+ for event in r.events:
28
+ if not isinstance(event, dict):
29
+ continue
30
+ data = event.get("event_data", {})
31
+ host = data.get("host")
32
+ if not host:
33
+ continue
34
+ if event["event"] == "runner_on_ok":
35
+ ok_hosts.add(host)
36
+ elif event["event"] == "runner_on_unreachable":
37
+ unreachable_hosts.add(host)
38
+
39
+ # Break early if all hosts responded
40
+ if ok_hosts and not unreachable_hosts:
41
+ break
42
+
43
+ logger.info("\nResults:")
44
+
45
+ if not ok_hosts and not unreachable_hosts:
46
+ logger.warning("No responses received. Are you connected to the VPN?")
47
+ return
48
+
49
+ for host in sorted(ok_hosts):
50
+ logger.info(f"[OK] {host}")
51
+ for host in sorted(unreachable_hosts):
52
+ logger.error(f"[UNREACHABLE] {host}")
@@ -0,0 +1,59 @@
1
+ import sys
2
+ import yaml
3
+ from pathlib import Path
4
+
5
+
6
+ def get_playbook_metadata(playbook_path: str):
7
+ try:
8
+ with open(playbook_path) as f:
9
+ playbook = yaml.safe_load(f)
10
+
11
+ if not playbook or not isinstance(playbook, list) or not playbook[0]:
12
+ return {"error": "Empty playbook"}
13
+
14
+ metadata = {
15
+ "hosts": playbook[0].get("hosts", "unknown"),
16
+ "description": playbook[0].get("vars", {}).get("description", ""),
17
+ "tasks": []
18
+ }
19
+
20
+ for task in playbook[0].get("tasks", []):
21
+ desc = task.get("vars", {}).get("description", task.get("name", "Unnamed Task"))
22
+ metadata["tasks"].append(desc)
23
+
24
+ return metadata
25
+
26
+ except Exception as e:
27
+ return {"error": str(e)}
28
+
29
+
30
+
31
+
32
+
33
+ def print_execution_plan(command: str, variables: dict, playbook_path: str, metadata=None):
34
+ if metadata is None:
35
+ metadata = get_playbook_metadata(playbook_path)
36
+
37
+ print("\nExecution Plan")
38
+ print("-" * 40)
39
+ print(f"Command : {command}")
40
+ print(f"Playbook : {playbook_path}")
41
+
42
+ if "error" in metadata:
43
+ print(f"Warning : {metadata['error']}")
44
+ else:
45
+ print(f"Hosts : {metadata['hosts']}")
46
+ print(f"Description : {metadata['description']}")
47
+ print("Steps :")
48
+ for idx, desc in enumerate(metadata['tasks'], start=1):
49
+ print(f" {idx}. {desc}")
50
+
51
+ if variables:
52
+ print("\nVariables:")
53
+ for k, v in variables.items():
54
+ print(f" {k:10}: {v}")
55
+
56
+ confirm = input("\nProceed with this execution plan? [y/N]: ").strip().lower()
57
+ if confirm != "y":
58
+ print("Aborted by user.")
59
+ sys.exit(0)
File without changes
@@ -0,0 +1,45 @@
1
+ import ansible_runner
2
+ import sys
3
+ from pathlib import Path
4
+ import logging
5
+ from dmtri.paths import INVENTORY_FILE
6
+
7
+
8
+ logger = logging.getLogger(__name__)
9
+ def run_hook(playbook_name: Path, vars: dict,inventory: Path = INVENTORY_FILE) -> None:
10
+ """
11
+ Run an Ansible playbook using ansible_runner.run_command, bypassing the project layout.
12
+ """
13
+
14
+ # Build the extra vars string manually
15
+ extra_vars = []
16
+ for key, value in vars.items():
17
+ if isinstance(value, list):
18
+ value = ",".join(value)
19
+ extra_vars.extend(["-e", f"{key}='{value}'"])
20
+
21
+ cmd = [
22
+ "ansible-playbook",
23
+ str(playbook_name.resolve()),
24
+ "-i",
25
+ str(inventory.resolve()),
26
+
27
+ ] + extra_vars
28
+
29
+
30
+ logger.info(f"Running: {' '.join(str(x) for x in cmd)}")
31
+
32
+
33
+ out, err, rc = ansible_runner.run_command(
34
+ executable_cmd="ansible-playbook",
35
+ cmdline_args=cmd[1:],
36
+ input_fd=sys.stdin,
37
+ output_fd=sys.stdout,
38
+ error_fd=sys.stderr,
39
+ )
40
+
41
+ if rc != 0:
42
+ logger.error(f"Playbook {playbook_name} failed with return code {rc}")
43
+ sys.exit(rc)
44
+
45
+ logger.info(f"Playbook {playbook_name} completed successfully")
@@ -0,0 +1,49 @@
1
+ from pathlib import Path
2
+
3
+ MODULE_DIR = Path(__file__).resolve().parent
4
+ SRC_DIR = MODULE_DIR.parent
5
+
6
+ # Directories
7
+ PLAYBOOKS_DIR = SRC_DIR / "playbooks"
8
+ INVENTORY_DIR = SRC_DIR / "inventory"
9
+
10
+ # Inventory file
11
+ INVENTORY_FILE = INVENTORY_DIR / "hosts.ini"
12
+
13
+ # Specific playbooks
14
+ PLAYBOOK_TRACK = PLAYBOOKS_DIR / "track.yml"
15
+ PLAYBOOK_LIST_SDS = PLAYBOOKS_DIR / "list_sds_files.yml"
16
+
17
+ # Refresh Data playbooks
18
+ PLAYBOOK_SEEDPSD_REFRESH = PLAYBOOKS_DIR / "refresh" / "seedpsd_refresh.yml"
19
+ PLAYBOOK_WFCATALOG_REFRESH = PLAYBOOKS_DIR / "refresh" / "wfcatalog_refresh.yml"
20
+ PLAYBOOK_AVAILABILITY_REFRESH = PLAYBOOKS_DIR / "refresh" / "availability_refresh.yml"
21
+ # Refresh metadata playbooks
22
+ PLAYBOOK_METADATA_REFRESH = PLAYBOOKS_DIR / "refresh" / "seedpsd_metadata_refresh.yml"
23
+
24
+ # Clean playbooks
25
+ PLAYBOOK_SEEDPSD_CLEAN = PLAYBOOKS_DIR / "clean" /"seedpsd_clean.yml"
26
+ PLAYBOOK_WFCATALOG_CLEAN = PLAYBOOKS_DIR / "clean" / "wfcatalog_clean.yml"
27
+ PLAYBOOK_AVAILABILITY_CLEAN = PLAYBOOKS_DIR / "clean" / "availability_clean.yml"
28
+
29
+ # Group playbooks by command
30
+ COMMAND_PLAYBOOKS = {
31
+ "refresh": {
32
+ "data": [
33
+ PLAYBOOK_SEEDPSD_REFRESH,
34
+ PLAYBOOK_WFCATALOG_REFRESH,
35
+ PLAYBOOK_AVAILABILITY_REFRESH,
36
+ ],
37
+ "metadata": [
38
+ PLAYBOOK_METADATA_REFRESH,
39
+ ]
40
+ },
41
+ "clean": [
42
+ PLAYBOOK_SEEDPSD_CLEAN,
43
+ PLAYBOOK_WFCATALOG_CLEAN,
44
+ PLAYBOOK_AVAILABILITY_CLEAN,
45
+ ],
46
+ "track": [
47
+ PLAYBOOK_TRACK
48
+ ]
49
+ }