summaryrefslogtreecommitdiff
path: root/ironic_python_agent/utils.py
diff options
context:
space:
mode:
authorDmitry Tantsur <dtantsur@protonmail.com>2021-02-12 17:00:40 +0100
committerDmitry Tantsur <dtantsur@protonmail.com>2021-02-16 16:56:52 +0100
commit59cb08fd288a23f31e8cfdd5aa57d979c5a3daff (patch)
tree3f4b9a6b795337a776aea10525f1ea80710f27ba /ironic_python_agent/utils.py
parent13c3c60ff1716cb25d0a33e85089304ae49ef8e2 (diff)
downloadironic-python-agent-59cb08fd288a23f31e8cfdd5aa57d979c5a3daff.tar.gz
New deploy step for injecting arbitrary files
This change adds a deploy step inject_files that adds a flexible way to inject files into the instance. Change-Id: I0e70a2cbc13744195c9493a48662e465ec010dbe Story: #2008611 Task: #41794
Diffstat (limited to 'ironic_python_agent/utils.py')
-rw-r--r--ironic_python_agent/utils.py41
1 files changed, 41 insertions, 0 deletions
diff --git a/ironic_python_agent/utils.py b/ironic_python_agent/utils.py
index a8712a6a..a5da83d6 100644
--- a/ironic_python_agent/utils.py
+++ b/ironic_python_agent/utils.py
@@ -35,6 +35,8 @@ from oslo_log import log as logging
from oslo_serialization import base64
from oslo_serialization import jsonutils
from oslo_utils import units
+import requests
+import tenacity
from ironic_python_agent import errors
@@ -811,3 +813,42 @@ def create_partition_table(dev_name, partition_table_type):
msg = "Failed to create partition table on {}: {}".format(
dev_name, e)
raise errors.CommandExecutionError(msg)
+
+
+class StreamingClient:
+ """A wrapper around HTTP client with TLS, streaming and error handling."""
+
+ _CHUNK_SIZE = 1 * units.Mi
+
+ def __init__(self, verify_ca=True):
+ if verify_ca:
+ self.verify, self.cert = get_ssl_client_options(CONF)
+ else:
+ self.verify, self.cert = False, None
+
+ @contextlib.contextmanager
+ def __call__(self, url):
+ """Execute a GET request and start streaming.
+
+ :param url: Target URL.
+ :return: A generator yielding chunks of data.
+ """
+ @tenacity.retry(
+ retry=tenacity.retry_if_exception_type(requests.ConnectionError),
+ stop=tenacity.stop_after_attempt(
+ CONF.image_download_connection_retries + 1),
+ wait=tenacity.wait_fixed(
+ CONF.image_download_connection_retry_interval),
+ reraise=True)
+ def _get_with_retries():
+ return requests.get(url, verify=self.verify, cert=self.cert,
+ stream=True,
+ timeout=CONF.image_download_connection_timeout)
+
+ try:
+ with _get_with_retries() as resp:
+ resp.raise_for_status()
+ yield resp.iter_content(self._CHUNK_SIZE)
+ except requests.RequestException as exc:
+ raise errors.CommandExecutionError(
+ "Unable to read data from %s: %s" % (url, exc))