Skip to content

Commit

Permalink
api: u.pro.config.v1
Browse files Browse the repository at this point in the history
Api endpoint to provide users with the pro configuration information
  • Loading branch information
dheyay authored and orndorffgrant committed Sep 24, 2024
1 parent 2312a49 commit ccc0264
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 18 deletions.
120 changes: 120 additions & 0 deletions features/api/status_config.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
Feature: Config status api

Scenario Outline: u.pro.config.v1
Given a `<release>` `<machine_type>` machine with ubuntu-advantage-tools installed
When I run `pro api u.pro.config.v1` with sudo
Then API data field output matches regexp:
"""
{
"attributes": {
"apt_news": true,
"apt_news_url": "https://motd.ubuntu.com/aptnews.json",
"global_apt_http_proxy": null,
"global_apt_https_proxy": null,
"http_proxy": null,
"https_proxy": null,
"metering_timer": 14400,
"ua_apt_http_proxy": null,
"ua_apt_https_proxy": null,
"update_messaging_timer": 21600
},
"meta": {
"environment_vars": []
},
"type": "Config"
}
"""
When I run `pro config set apt_news=false` with sudo
When I run `pro api u.pro.config.v1` with sudo
Then API data field output matches regexp:
"""
{
"attributes": {
"apt_news": false,
"apt_news_url": "https://motd.ubuntu.com/aptnews.json",
"global_apt_http_proxy": null,
"global_apt_https_proxy": null,
"http_proxy": null,
"https_proxy": null,
"metering_timer": 14400,
"ua_apt_http_proxy": null,
"ua_apt_https_proxy": null,
"update_messaging_timer": 21600
},
"meta": {
"environment_vars": []
},
"type": "Config"
}
"""

Examples: ubuntu release
| release | machine_type |
| xenial | lxd-container |
| bionic | lxd-container |
| focal | lxd-container |
| jammy | lxd-container |
| noble | lxd-container |

Scenario Outline: Check proxy settings as sudo/non-root
Given a `<release>` `<machine_type>` machine with ubuntu-advantage-tools installed
Given a `focal` `lxd-container` machine named `proxy`
When I apt install `squid` on the `proxy` machine
And I add this text on `/etc/squid/squid.conf` on `proxy` above `http_access deny all`:
"""
dns_v4_first on\nacl all src 0.0.0.0\/0\nhttp_access allow all
"""
And I run `systemctl restart squid.service` `with sudo` on the `proxy` machine
And I run `pro config set http_proxy=http://someuser:somepassword@$behave_var{machine-ip proxy}:3128` with sudo
When I run `pro api u.pro.config.v1` with sudo
Then API data field output matches regexp:
"""
{
"attributes": {
"apt_news": true,
"apt_news_url": "https://motd.ubuntu.com/aptnews.json",
"global_apt_http_proxy": null,
"global_apt_https_proxy": null,
"http_proxy": "http://someuser:somepassword@$behave_var{machine-ip proxy}:3128",
"https_proxy": null,
"metering_timer": 14400,
"ua_apt_http_proxy": null,
"ua_apt_https_proxy": null,
"update_messaging_timer": 21600
},
"meta": {
"environment_vars": []
},
"type": "Config"
}
"""
When I run `pro api u.pro.config.v1` as non-root
Then API data field output matches regexp:
"""
{
"attributes": {
"apt_news": true,
"apt_news_url": "https://motd.ubuntu.com/aptnews.json",
"global_apt_http_proxy": null,
"global_apt_https_proxy": null,
"http_proxy": "<REDACTED>",
"https_proxy": null,
"metering_timer": 14400,
"ua_apt_http_proxy": null,
"ua_apt_https_proxy": null,
"update_messaging_timer": 21600
},
"meta": {
"environment_vars": []
},
"type": "Config"
}
"""

Examples: ubuntu release
| release | machine_type |
| xenial | lxd-container |
| bionic | lxd-container |
| focal | lxd-container |
| jammy | lxd-container |
| noble | lxd-container |
1 change: 1 addition & 0 deletions uaclient/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"u.pro.attach.magic.revoke.v1",
"u.pro.attach.magic.wait.v1",
"u.pro.attach.token.full_token_attach.v1",
"u.pro.config.v1",
"u.pro.detach.v1",
"u.pro.packages.summary.v1",
"u.pro.packages.updates.v1",
Expand Down
Empty file.
145 changes: 145 additions & 0 deletions uaclient/api/u/pro/config/v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import logging
from typing import Optional

from uaclient import util
from uaclient.api.api import APIEndpoint
from uaclient.api.data_types import AdditionalInfo
from uaclient.config import UA_CONFIGURABLE_KEYS, UAConfig
from uaclient.data_types import (
BoolDataValue,
DataObject,
Field,
IntDataValue,
StringDataValue,
)

LOG = logging.getLogger(util.replace_top_level_logger_name(__name__))


class ConfigInfo(DataObject, AdditionalInfo):
fields = [
Field("http_proxy", StringDataValue, required=False, doc="HTTP proxy"),
Field(
"https_proxy", StringDataValue, required=False, doc="HTTPS proxy"
),
Field(
"ua_apt_http_proxy",
StringDataValue,
required=False,
doc="Ubuntu Pro APT HTTP proxy",
),
Field(
"ua_apt_https_proxy",
StringDataValue,
required=False,
doc="Ubuntu Pro APT HTTPS proxy",
),
Field(
"global_apt_http_proxy",
StringDataValue,
required=False,
doc="Global APT HTTP proxy",
),
Field(
"global_apt_https_proxy",
StringDataValue,
required=False,
doc="Global APT HTTPS proxy",
),
Field("apt_news", BoolDataValue, required=False, doc="APT news"),
Field(
"apt_news_url", StringDataValue, required=False, doc="APT news URL"
),
Field(
"metering_timer",
IntDataValue,
required=False,
doc="Metering timer",
),
Field(
"update_messaging_timer",
IntDataValue,
required=False,
doc="Update messaging timer",
),
]

def __init__(
self,
*,
http_proxy: Optional[str] = None,
https_proxy: Optional[str] = None,
ua_apt_http_proxy: Optional[str] = None,
ua_apt_https_proxy: Optional[str] = None,
global_apt_http_proxy: Optional[str] = None,
global_apt_https_proxy: Optional[str] = None,
update_messaging_timer: Optional[int] = None,
metering_timer: Optional[int] = None,
apt_news: Optional[bool] = None,
apt_news_url: Optional[str] = None
):
self.http_proxy = http_proxy
self.https_proxy = https_proxy
self.ua_apt_http_proxy = ua_apt_http_proxy
self.ua_apt_https_proxy = ua_apt_https_proxy
self.global_apt_http_proxy = global_apt_http_proxy
self.global_apt_https_proxy = global_apt_https_proxy
self.update_messaging_timer = update_messaging_timer
self.metering_timer = metering_timer
self.apt_news = apt_news
self.apt_news_url = apt_news_url


def config() -> ConfigInfo:
return _config(UAConfig())


def _config(cfg: UAConfig) -> ConfigInfo:
"""This endpoint returns the current user configuration"""
pro_config = {}
for key in UA_CONFIGURABLE_KEYS:
if hasattr(cfg, key):
pro_config[key] = getattr(cfg, key)

return ConfigInfo.from_dict(pro_config)


endpoint = APIEndpoint(
version="v1",
name="Config",
fn=_config,
options_cls=None,
)

_doc = {
"introduced_in": "35",
"requires_network": False,
"example_python": """
from uaclient.api.u.pro.config.v1 import config
result = config()
""", # noqa: E501
"result_class": ConfigInfo,
"exceptions": [],
"example_cli": "pro api u.pro.config.v1",
"example_json": """
{
"attributes": {
"apt_news": true,
"apt_news_url": "https://motd.ubuntu.com/aptnews.json",
"global_apt_http_proxy": null,
"global_apt_https_proxy": null,
"http_proxy": null,
"https_proxy": null,
"metering_timer": 14400,
"ua_apt_http_proxy": null,
"ua_apt_https_proxy": null,
"update_messaging_timer": 21600
},
"meta": {
"environment_vars": []
},
"type": "Config"
}
""",
}
12 changes: 7 additions & 5 deletions uaclient/cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
http,
messages,
)
from uaclient.api.u.pro.config.v1 import _config
from uaclient.apt import AptProxyScope
from uaclient.cli import cli_util
from uaclient.cli.commands import ProArgument, ProArgumentGroup, ProCommand
Expand Down Expand Up @@ -36,6 +37,7 @@ def action_config_show(args, *, cfg, **kwargs):
:return: 0 on success
:raise UbuntuProError: on invalid keys
"""
pro_config = _config(cfg)
if args.key: # limit reporting config to a single config key
if args.key not in config.UA_CONFIGURABLE_KEYS:
raise exceptions.InvalidArgChoice(
Expand All @@ -44,7 +46,7 @@ def action_config_show(args, *, cfg, **kwargs):
)
print(
"{key} {value}".format(
key=args.key, value=getattr(cfg, args.key, None)
key=args.key, value=getattr(pro_config, args.key, None)
)
)
return 0
Expand All @@ -53,11 +55,11 @@ def action_config_show(args, *, cfg, **kwargs):
row_tmpl = "{key: <" + col_width + "} {value}"

for key in config.UA_CONFIGURABLE_KEYS:
print(row_tmpl.format(key=key, value=getattr(cfg, key, None)))
print(row_tmpl.format(key=key, value=getattr(pro_config, key, None)))

if (cfg.global_apt_http_proxy or cfg.global_apt_https_proxy) and (
cfg.ua_apt_http_proxy or cfg.ua_apt_https_proxy
):
if (
pro_config.global_apt_http_proxy or pro_config.global_apt_https_proxy
) and (pro_config.ua_apt_http_proxy or pro_config.ua_apt_https_proxy):
print(messages.CLI_CONFIG_GLOBAL_XOR_UA_PROXY)


Expand Down
8 changes: 7 additions & 1 deletion uaclient/cli/tests/test_cli_config_show.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from uaclient.cli import main
from uaclient.cli.config import show_subcommand
from uaclient.files.user_config_file import UserConfigData

M_PATH = "uaclient.cli."

Expand Down Expand Up @@ -44,8 +45,13 @@ class TestActionConfigShow:
"global_apt_https_proxy",
),
)
@mock.patch(
"uaclient.files.user_config_file.UserConfigFileObject.public_config",
new_callable=mock.PropertyMock,
return_value=UserConfigData(),
)
def test_show_values_and_limit_when_optional_key_provided(
self, optional_key, FakeConfig, capsys
self, _m_public_config, optional_key, FakeConfig, capsys
):
cfg = FakeConfig()
cfg.user_config.http_proxy = "http://http_proxy"
Expand Down
17 changes: 5 additions & 12 deletions uaclient/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
util,
version,
)
from uaclient.api.u.pro.config.v1 import _config
from uaclient.api.u.pro.status.is_attached.v1 import _is_attached
from uaclient.api.u.pro.subscription.v1 import _subscription
from uaclient.config import UA_CONFIGURABLE_KEYS, UAConfig
from uaclient.config import UAConfig
from uaclient.contract import get_available_resources, get_contract_information
from uaclient.defaults import ATTACH_FAIL_DATE_FORMAT, PRINT_WRAP_WIDTH
from uaclient.entitlements import entitlement_factory
Expand All @@ -27,12 +28,7 @@
UserFacingConfigStatus,
UserFacingStatus,
)
from uaclient.files import (
machine_token,
notices,
state_files,
user_config_file,
)
from uaclient.files import machine_token, notices, state_files
from uaclient.files.notices import Notice
from uaclient.messages import TxtColor

Expand Down Expand Up @@ -339,6 +335,7 @@ def _get_config_status(cfg) -> Dict[str, Any]:
status_desc = messages.ENABLE_REBOOT_REQUIRED_TMPL.format(
operation=operation
)

ret = {
"execution_status": status_val,
"execution_details": status_desc,
Expand All @@ -348,11 +345,7 @@ def _get_config_status(cfg) -> Dict[str, Any]:
"features": cfg.features,
}
# LP: #2004280 maintain backwards compatibility
ua_config = user_config_file.user_config.public_config.to_dict()
for key in UA_CONFIGURABLE_KEYS:
if hasattr(cfg, key) and ua_config[key] is None:
ua_config[key] = getattr(cfg, key)
ret["config"]["ua_config"] = ua_config
ret["config"]["ua_config"] = _config(cfg).to_dict()

return ret

Expand Down

0 comments on commit ccc0264

Please sign in to comment.