[sunbeam-machine] Add proxy configs
Add http_proxy, https_proxy, no_proxy as configuration to charm. Update the content of /etc/environment file on setting the proxy configs. If the proxy configuration is not set on sunbeam-machine, clear the corresponding configs from /etc/environment. Change-Id: I5ba444d87e199a4314439eddf513729138c40c3f
This commit is contained in:
parent
496d48a237
commit
ada047a90f
@ -6,4 +6,12 @@ options:
|
||||
debug:
|
||||
default: False
|
||||
type: boolean
|
||||
|
||||
http_proxy:
|
||||
description: Set HTTP_PROXY in /etc/environment
|
||||
type: string
|
||||
https_proxy:
|
||||
description: Set HTTPS_PROXY in /etc/environment
|
||||
type: string
|
||||
no_proxy:
|
||||
description: Set NO_PROXY in /etc/environment
|
||||
type: string
|
||||
|
@ -33,6 +33,7 @@ from ops.main import (
|
||||
main,
|
||||
)
|
||||
|
||||
ETC_ENVIRONMENT = "/etc/environment"
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -41,6 +42,7 @@ class SunbeamMachineCharm(sunbeam_charm.OSBaseOperatorCharm):
|
||||
|
||||
_state = ops.framework.StoredState()
|
||||
service_name = "sunbeam-machine"
|
||||
proxy_configs = ["http_proxy", "https_proxy", "no_proxy"]
|
||||
|
||||
def __init__(self, framework: ops.Framework) -> None:
|
||||
super().__init__(framework)
|
||||
@ -64,6 +66,34 @@ class SunbeamMachineCharm(sunbeam_charm.OSBaseOperatorCharm):
|
||||
logger.error("Error executing sysctl", exc_info=True)
|
||||
raise sunbeam_guard.BlockedExceptionError("Sysctl command failed")
|
||||
|
||||
def _on_config_changed(self, event: ops.ConfigChangedEvent):
|
||||
self.configure_charm(event)
|
||||
with open(ETC_ENVIRONMENT, mode="r", encoding="utf-8") as file:
|
||||
current_env = dict(
|
||||
line.strip().split("=", 1) for line in file if "=" in line
|
||||
)
|
||||
logger.info(f"Existing content of /etc/environment: {current_env}")
|
||||
|
||||
proxy = {p: v for p in self.proxy_configs if (v := self.config.get(p))}
|
||||
if all(
|
||||
proxy.get(p) == current_env.get(p.upper())
|
||||
for p in self.proxy_configs
|
||||
):
|
||||
return
|
||||
|
||||
# Remove proxies not set
|
||||
not_set_proxies = self.proxy_configs - proxy.keys()
|
||||
for p in not_set_proxies:
|
||||
if (p_upper := p.upper()) in current_env:
|
||||
del current_env[p_upper]
|
||||
|
||||
# Capitalise proxy keys and update env
|
||||
proxy_in_caps = {k.upper(): v for k, v in proxy.items()}
|
||||
current_env.update(proxy_in_caps)
|
||||
|
||||
with open(ETC_ENVIRONMENT, mode="w", encoding="utf-8") as file:
|
||||
file.write("\n".join([f"{k}={v}" for k, v in current_env.items()]))
|
||||
|
||||
def _on_remove(self, event: ops.RemoveEvent):
|
||||
self.sysctl.remove()
|
||||
|
||||
|
@ -14,6 +14,11 @@
|
||||
|
||||
"""Tests for Sunbeam Machine charm."""
|
||||
|
||||
from unittest.mock import (
|
||||
mock_open,
|
||||
patch,
|
||||
)
|
||||
|
||||
import charm
|
||||
import ops_sunbeam.test_utils as test_utils
|
||||
|
||||
@ -30,7 +35,7 @@ class _SunbeamMachineCharm(charm.SunbeamMachineCharm):
|
||||
class TestCharm(test_utils.CharmTestCase):
|
||||
"""Classes for testing Sunbeam Machine charm."""
|
||||
|
||||
PATCHES = []
|
||||
PATCHES = ["sysctl"]
|
||||
|
||||
def setUp(self):
|
||||
"""Setup Sunbeam machine tests."""
|
||||
@ -46,5 +51,108 @@ class TestCharm(test_utils.CharmTestCase):
|
||||
|
||||
def test_initial(self):
|
||||
"""Bootstrap test initial."""
|
||||
self.harness.begin_with_initial_hooks()
|
||||
file_content_dict = {"PATH": "FAKEPATH"}
|
||||
env_file_content = "\n".join(
|
||||
f"{k}={v}" for k, v in file_content_dict.items()
|
||||
)
|
||||
|
||||
with patch(
|
||||
"builtins.open", new_callable=mock_open, read_data=env_file_content
|
||||
) as mock_file:
|
||||
self.harness.begin_with_initial_hooks()
|
||||
mock_file().write.assert_not_called()
|
||||
|
||||
self.assertTrue(self.harness.charm.bootstrapped())
|
||||
|
||||
def test_proxy_settings(self):
|
||||
"""Test setting proxies."""
|
||||
# test_data is a tuple of /etc/environment file content as dict, proxy config as dict,
|
||||
# expected content as dict
|
||||
# As the below tests are run in loop as subtests, they act as juju config commands.
|
||||
# Means the configs set in the previous test data remains until it is reset by
|
||||
# specifying config as empty string.
|
||||
test_data = [
|
||||
# Case 1: No proxy in environment file, set http_proxy, https_proxy
|
||||
(
|
||||
{"PATH": "FAKEPATH"},
|
||||
{
|
||||
"http_proxy": "http://proxyserver:3128",
|
||||
"https_proxy": "http://proxyserver:3128",
|
||||
},
|
||||
{
|
||||
"PATH": "FAKEPATH",
|
||||
"HTTP_PROXY": "http://proxyserver:3128",
|
||||
"HTTPS_PROXY": "http://proxyserver:3128",
|
||||
},
|
||||
),
|
||||
# Case 2: Add no_proxy to above configuration
|
||||
(
|
||||
{
|
||||
"PATH": "FAKEPATH",
|
||||
"HTTP_PROXY": "http://proxyserver:3128",
|
||||
"HTTPS_PROXY": "http://proxyserver:3128",
|
||||
},
|
||||
{"no_proxy": "localhost,127.0.0.1"},
|
||||
{
|
||||
"PATH": "FAKEPATH",
|
||||
"HTTP_PROXY": "http://proxyserver:3128",
|
||||
"HTTPS_PROXY": "http://proxyserver:3128",
|
||||
"NO_PROXY": "localhost,127.0.0.1",
|
||||
},
|
||||
),
|
||||
# Case 3: Update http proxy to different value
|
||||
(
|
||||
{
|
||||
"PATH": "FAKEPATH",
|
||||
"HTTP_PROXY": "http://proxyserver:3128",
|
||||
"HTTPS_PROXY": "http://proxyserver:3128",
|
||||
"NO_PROXY": "localhost,127.0.0.1",
|
||||
},
|
||||
{
|
||||
"http_proxy": "http://proxyserver:3120",
|
||||
"https_proxy": "http://proxyserver:3128",
|
||||
},
|
||||
{
|
||||
"PATH": "FAKEPATH",
|
||||
"HTTP_PROXY": "http://proxyserver:3120",
|
||||
"HTTPS_PROXY": "http://proxyserver:3128",
|
||||
"NO_PROXY": "localhost,127.0.0.1",
|
||||
},
|
||||
),
|
||||
# Case 4: Reset the no_proxy config
|
||||
(
|
||||
{
|
||||
"PATH": "FAKEPATH",
|
||||
"HTTP_PROXY": "http://proxyserver:3120",
|
||||
"HTTPS_PROXY": "http://proxyserver:3128",
|
||||
"NO_PROXY": "localhost,127.0.0.1",
|
||||
},
|
||||
{"no_proxy": ""},
|
||||
{
|
||||
"PATH": "FAKEPATH",
|
||||
"HTTP_PROXY": "http://proxyserver:3120",
|
||||
"HTTPS_PROXY": "http://proxyserver:3128",
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
with patch(
|
||||
"builtins.open", new_callable=mock_open, read_data=""
|
||||
) as mock_file:
|
||||
self.harness.begin_with_initial_hooks()
|
||||
|
||||
for index, d in enumerate(test_data):
|
||||
with self.subTest(msg=f"test_proxy_settings-{index}", data=d):
|
||||
env_file_content = "\n".join(
|
||||
f"{k}={v}" for k, v in d[0].items()
|
||||
)
|
||||
expected_content = "\n".join(
|
||||
f"{k}={v}" for k, v in d[2].items()
|
||||
)
|
||||
with patch(
|
||||
"builtins.open",
|
||||
new_callable=mock_open,
|
||||
read_data=env_file_content,
|
||||
) as mock_file:
|
||||
self.harness.update_config(d[1])
|
||||
mock_file().write.assert_called_with(expected_content)
|
||||
|
Loading…
Reference in New Issue
Block a user