Skip to content

Commit dba4a13

Browse files
committed
add k8s utility for exporting datadir
tars a datadir based on a passed in filter (if no filter, zip everything) and copies the zip to the users host.
1 parent c1c7009 commit dba4a13

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

src/warnet/k8s.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import json
2+
import os
23
import tempfile
34
from pathlib import Path
45

56
import yaml
67
from kubernetes import client, config
78
from kubernetes.client.models import CoreV1Event, V1PodList
89
from kubernetes.dynamic import DynamicClient
10+
from kubernetes.stream import stream
911

1012
from .constants import DEFAULT_NAMESPACE, KUBECONFIG
1113
from .process import run_command, stream_command
@@ -115,3 +117,113 @@ def get_default_namespace() -> str:
115117
command = "kubectl config view --minify -o jsonpath='{..namespace}'"
116118
kubectl_namespace = run_command(command)
117119
return kubectl_namespace if kubectl_namespace else DEFAULT_NAMESPACE
120+
121+
122+
def snapshot_bitcoin_datadir(
123+
pod_name: str, chain: str, local_path: str = "./", filters: list[str] = None
124+
) -> None:
125+
namespace = get_default_namespace()
126+
sclient = get_static_client()
127+
128+
try:
129+
sclient.read_namespaced_pod(name=pod_name, namespace=namespace)
130+
131+
# Filter down to the specified list of directories and files
132+
# This allows for creating snapshots of only the relevant data, e.g.,
133+
# we may want to snapshot the blocks but not snapshot peers.dat or the node
134+
# wallets.
135+
#
136+
# TODO: never snapshot bitcoin.conf, as this is managed by the helm config
137+
if filters:
138+
find_command = [
139+
"find",
140+
f"/root/.bitcoin/{chain}",
141+
"(",
142+
"-type",
143+
"f",
144+
"-o",
145+
"-type",
146+
"d",
147+
")",
148+
"(",
149+
"-name",
150+
filters[0],
151+
]
152+
for f in filters[1:]:
153+
find_command.extend(["-o", "-name", f])
154+
find_command.append(")")
155+
else:
156+
# If no filters, get everything in the Bitcoin directory (TODO: exclude bitcoin.conf)
157+
find_command = ["find", f"/root/.bitcoin/{chain}"]
158+
159+
resp = stream(
160+
sclient.connect_get_namespaced_pod_exec,
161+
pod_name,
162+
namespace,
163+
command=find_command,
164+
stderr=True,
165+
stdin=False,
166+
stdout=True,
167+
tty=False,
168+
_preload_content=False,
169+
)
170+
171+
file_list = []
172+
while resp.is_open():
173+
resp.update(timeout=1)
174+
if resp.peek_stdout():
175+
file_list.extend(resp.read_stdout().strip().split("\n"))
176+
if resp.peek_stderr():
177+
print(f"Error: {resp.read_stderr()}")
178+
179+
resp.close()
180+
if not file_list:
181+
print("No matching files or directories found.")
182+
return
183+
tar_command = ["tar", "-czf", "/tmp/bitcoin_data.tar.gz", "-C", f"/root/.bitcoin/{chain}"]
184+
tar_command.extend(
185+
[os.path.relpath(f, f"/root/.bitcoin/{chain}") for f in file_list if f.strip()]
186+
)
187+
resp = stream(
188+
sclient.connect_get_namespaced_pod_exec,
189+
pod_name,
190+
namespace,
191+
command=tar_command,
192+
stderr=True,
193+
stdin=False,
194+
stdout=True,
195+
tty=False,
196+
_preload_content=False,
197+
)
198+
while resp.is_open():
199+
resp.update(timeout=1)
200+
if resp.peek_stdout():
201+
print(f"Tar output: {resp.read_stdout()}")
202+
if resp.peek_stderr():
203+
print(f"Error: {resp.read_stderr()}")
204+
resp.close()
205+
local_file_path = Path(local_path) / f"{pod_name}_bitcoin_data.tar.gz"
206+
copy_command = (
207+
f"kubectl cp {namespace}/{pod_name}:/tmp/bitcoin_data.tar.gz {local_file_path}"
208+
)
209+
if not stream_command(copy_command):
210+
raise Exception("Failed to copy tar file from pod to local machine")
211+
212+
print(f"Bitcoin data exported successfully to {local_file_path}")
213+
cleanup_command = ["rm", "/tmp/bitcoin_data.tar.gz"]
214+
stream(
215+
sclient.connect_get_namespaced_pod_exec,
216+
pod_name,
217+
namespace,
218+
command=cleanup_command,
219+
stderr=True,
220+
stdin=False,
221+
stdout=True,
222+
tty=False,
223+
)
224+
225+
print("To untar and repopulate the directory, use the following command:")
226+
print(f"tar -xzf {local_file_path} -C /path/to/destination/.bitcoin/{chain}")
227+
228+
except Exception as e:
229+
print(f"An error occurred: {str(e)}")

0 commit comments

Comments
 (0)