Skip to content

Circuit breaker plugin #688

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 46 commits into
base: main
Choose a base branch
from

Conversation

Camillarhi
Copy link

No description provided.

@Camillarhi Camillarhi mentioned this pull request Mar 6, 2025
@pinheadmz
Copy link
Contributor

weird error trying to warnet deploy resources/networks/hello/ but might be related to #689 like, plugin.py needs chmod a+x or something.

Queuing postNetwork plugin command: hello with {'entrypoint': '../../plugins/hello', 'helloTo': 'postNetwork!', 'podName': 'hello-post-network'}
Starting postNetwork plugins
Completed postNetwork plugins
Queuing postDeploy plugin command: hello with {'entrypoint': '../../plugins/hello', 'podName': 'hello-post-deploy', 'helloTo': 'postDeploy!'}
Queuing postDeploy plugin command: simln with {'entrypoint': '../../plugins/simln', 'activity': '[{"source": "tank-0003-ln", "destination": "tank-0005-ln", "interval_secs": 1, "amount_msat": 2000}]'}
Queuing postDeploy plugin command: circuitbreaker with {'entrypoint': '../../plugins/circuitbreaker', 'podName': 'circuitbreaker-pod', 'rpcserver': '172.29.34.166:10009', 'httplisten': '0.0.0.0:9235'}
Starting postDeploy plugins
Process Process-11:
Traceback (most recent call last):
  File "/opt/homebrew/Cellar/[email protected]/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/multiprocessing/process.py", line 313, in _bootstrap
    self.run()
    ~~~~~~~~^^
  File "/opt/homebrew/Cellar/[email protected]/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/matthewzipkin/Desktop/work/warnet/src/warnet/process.py", line 7, in run_command
    raise Exception(result.stderr)
Exception: bash: line 1: resources/networks/hello/../../plugins/circuitbreaker/plugin.py: Permission denied

@Camillarhi
Copy link
Author

weird error trying to warnet deploy resources/networks/hello/ but might be related to #689 like, plugin.py needs chmod a+x or something.

Queuing postNetwork plugin command: hello with {'entrypoint': '../../plugins/hello', 'helloTo': 'postNetwork!', 'podName': 'hello-post-network'}
Starting postNetwork plugins
Completed postNetwork plugins
Queuing postDeploy plugin command: hello with {'entrypoint': '../../plugins/hello', 'podName': 'hello-post-deploy', 'helloTo': 'postDeploy!'}
Queuing postDeploy plugin command: simln with {'entrypoint': '../../plugins/simln', 'activity': '[{"source": "tank-0003-ln", "destination": "tank-0005-ln", "interval_secs": 1, "amount_msat": 2000}]'}
Queuing postDeploy plugin command: circuitbreaker with {'entrypoint': '../../plugins/circuitbreaker', 'podName': 'circuitbreaker-pod', 'rpcserver': '172.29.34.166:10009', 'httplisten': '0.0.0.0:9235'}
Starting postDeploy plugins
Process Process-11:
Traceback (most recent call last):
  File "/opt/homebrew/Cellar/[email protected]/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/multiprocessing/process.py", line 313, in _bootstrap
    self.run()
    ~~~~~~~~^^
  File "/opt/homebrew/Cellar/[email protected]/3.13.1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/matthewzipkin/Desktop/work/warnet/src/warnet/process.py", line 7, in run_command
    raise Exception(result.stderr)
Exception: bash: line 1: resources/networks/hello/../../plugins/circuitbreaker/plugin.py: Permission denied

Yeah, I believe this issue is related to #689. To resolve it, I ran chmod a+x on the relevant plugin files and converted line Endings with dos2unix. That got everything working for me.

@willcl-ark willcl-ark mentioned this pull request Mar 9, 2025
@willcl-ark
Copy link
Contributor

willcl-ark commented Mar 9, 2025

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

No conflicts as of last run.

@Camillarhi Camillarhi force-pushed the circuit-breaker-plugin branch from ce43d60 to 0418553 Compare March 19, 2025 01:22
Copy link
Contributor

@pinheadmz pinheadmz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed a few things to check. Coudn't get the branch to run locally probably just because of the image error?

Also checkout the legacy branch for how we did integration tests for circuitbreaker:

https://github.com/bitcoin-dev-project/warnet/blob/legacy/test/ln_test.py#L34-L39

Copy link
Contributor

@pinheadmz pinheadmz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, thanks for the update. Be sure to check out the legacy ln test that covered circuitbreaker: https://github.com/bitcoin-dev-project/warnet/blob/legacy/test/ln_test.py

I don't think the hello network is very useful actually, and it would be better to add the circuit breaker plugin to one of the networks in test/data so it can actually be run and tested by ci.

Comment on lines +61 to +62
- name: shared-volume
mountPath: /root/.lnd/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might not actually need this shared volume at all. Because lnd and circuitbreaker are in the same pod, they already share a filesystem. So you'd just need to configure circuitbreaker to read from the right location. There's also apparently an issue getting the network value into the config.

When I warnet deploy resources/networks/hello I see this error in the circuitbreaker container:

2025-04-29T13:54:23.979Z    INFO    Circuit Breaker starting    {"version": ""}
2025-04-29T13:54:23.979Z    INFO    Opening database    {"path": "/root/.circuitbreaker/circuitbreaker.db"}
2025-04-29T13:54:24.007Z    INFO    Applied migrations    {"count": 4}
2025-04-29T13:54:24.007Z    ERROR    Unexpected exit    {"err": "unable to read macaroon path (check the network setting!): open /root/.lnd/data/chain/bitcoin/regtest/admin.macaroon: no such file or directory"}
main.main
    /src/main.go:152
runtime.main
    /usr/local/go/src/runtime/proc.go:250
Stream closed EOF for default/tank-0003-ln (circuitbreaker)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Camillarhi did you try removing the shared volume?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking into other comments. I will look into this as soon as I can

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pinheadmz , After testing both approaches, I've confirmed that a shared volume is necessary for reliable file access between containers in the same pod. While containers in a pod share the same network namespace, they maintain separate filesystems unless explicitly shared through volumes.

@Camillarhi
Copy link
Author

Looking good, thanks for the update. Be sure to check out the legacy ln test that covered circuitbreaker: https://github.com/bitcoin-dev-project/warnet/blob/legacy/test/ln_test.py

I don't think the hello network is very useful actually, and it would be better to add the circuit breaker plugin to one of the networks in test/data so it can actually be run and tested by ci.

Thanks. I have added circuitbreaker to a network and some unit tests for it has been included as well

Comment on lines +66 to +82
{{- if .Values.circuitbreaker.enabled }}
- name: circuitbreaker
image: {{ .Values.circuitbreaker.image | quote }}
imagePullPolicy: IfNotPresent
args:
- "--network={{ .Values.global.chain }}"
- "--rpcserver=localhost:{{ .Values.RPCPort }}"
- "--tlscertpath=/tls.cert"
- "--macaroonpath=/root/.lnd/data/chain/bitcoin/{{ .Values.global.chain }}/admin.macaroon"
- "--httplisten=0.0.0.0:{{ .Values.circuitbreaker.httpPort }}"
volumeMounts:
- name: shared-volume
mountPath: /root/.lnd/
- name: config
mountPath: /tls.cert
subPath: tls.cert
{{- end }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there an issue including circuitbreaker as extraContainers container?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was not able to access the value of the port and network variables as the extraContainers is being parsed by a YAML parser before Helm gets to process the templates.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm the whole point of those extraContainers was for the cb plugin ... :-/

Copy link
Author

@Camillarhi Camillarhi May 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I understand, but I could not access a dynamic network or port while using it. The current approach also gives the option of enabling circuitbreaker if needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pinheadmz I assume it is acceptable to define network(chain) in network.yaml or node-defaults.yaml based on user desired scenario. if so then extraContainers should be possible...

Comment on lines +157 to +175
try:
subprocess.run(
[
"kubectl",
"expose",
"pod",
pod_name,
"--name",
service_name,
"--port",
str(self.cb_port),
"--target-port",
str(self.cb_port),
],
check=True,
)
except subprocess.CalledProcessError as e:
self.log.error(f"Failed to create service: {e.stderr}")
raise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could add service.yaml definition instead of creating service on the fly...
image

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I will do this instead

Copy link
Contributor

@pinheadmz pinheadmz May 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is overkill. See the legacy test, you can just execute an API request form inside the cb container. (this exact code wont work any more but maybe gives a good hint)

warnet/test/ln_test.py

Lines 34 to 39 in 01195c2

def get_cb_forwards(self, index):
cmd = "wget -q -O - 127.0.0.1:9235/api/forwarding_history"
res = self.wait_for_rpc(
"exec_run", [index, ServiceType.CIRCUITBREAKER.value, cmd, self.network_name]
)
return json.loads(res)

Copy link
Author

@Camillarhi Camillarhi May 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into the legacy test but was unable to replicate it or access circuitbreaker through localhost(127.0.0.1) without port forwarding. I’ll do more research to figure out how to properly access it, but I’m also open to suggestions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could add a util funciton to k8s.py to execute an arbitrary command inside a container (surprised we dont have that alreaady actually....) and then execute the command curl 127.0.0.1/whatever/cb/api...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh right or do something like this in the test:

cmd = f"kubectl -n {namespace} exec {tank} --container {BITCOINCORE_CONTAINER} -- bitcoin-cli {method} {' '.join(map(str, params))}"
return run_command(cmd)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I will try this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants