ubuntu-pro: return number of packages and EOL ESM in /ubuntu_pro/info

We now rely on distro-info to find out the EOL ESM date on LTS releases.
This information is meant to be shown on the Ubuntu Pro screens ;
instead of hardcoded values.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
This commit is contained in:
Olivier Gayot 2024-02-13 11:03:52 +01:00
parent 7a5ff9e76a
commit a42ea0a685
6 changed files with 76 additions and 2 deletions

View File

@ -27,6 +27,7 @@ python3-bson
python3-coverage python3-coverage
python3-debian python3-debian
python3-dev python3-dev
python3-distro-info
python3-distutils-extra python3-distutils-extra
python3-flake8 python3-flake8
python3-gi python3-gi

View File

@ -132,6 +132,7 @@ parts:
- python3-attr - python3-attr
- python3-bson - python3-bson
- python3-debian - python3-debian
- python3-distro-info
- python3-jsonschema - python3-jsonschema
- python3-minimal - python3-minimal
- python3-oauthlib - python3-oauthlib

View File

@ -67,6 +67,7 @@ from subiquity.common.types import (
StorageResponseV2, StorageResponseV2,
TimeZoneInfo, TimeZoneInfo,
UbuntuProCheckTokenAnswer, UbuntuProCheckTokenAnswer,
UbuntuProGeneralInfo,
UbuntuProInfo, UbuntuProInfo,
UbuntuProResponse, UbuntuProResponse,
UPCSInitiateResponse, UPCSInitiateResponse,
@ -513,6 +514,10 @@ class API:
def POST() -> None: def POST() -> None:
... ...
class info:
def GET() -> UbuntuProGeneralInfo:
...
class identity: class identity:
def GET() -> IdentityData: def GET() -> IdentityData:
... ...

View File

@ -718,6 +718,13 @@ class UbuntuProCheckTokenStatus(enum.Enum):
UNKNOWN_ERROR = enum.auto() UNKNOWN_ERROR = enum.auto()
@attr.s(auto_attribs=True)
class UbuntuProGeneralInfo:
eol_esm_year: Optional[int]
universe_packages: int
main_packages: int
@attr.s(auto_attribs=True) @attr.s(auto_attribs=True)
class UPCSInitiateResponse: class UPCSInitiateResponse:
"""Response to Ubuntu Pro contract selection initiate request.""" """Response to Ubuntu Pro contract selection initiate request."""

View File

@ -13,17 +13,20 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest from unittest import mock
import jsonschema import jsonschema
from jsonschema.validators import validator_for from jsonschema.validators import validator_for
from subiquity.server.controllers.ubuntu_pro import UbuntuProController from subiquity.server.controllers.ubuntu_pro import UbuntuProController
from subiquity.server.dryrun import DRConfig from subiquity.server.dryrun import DRConfig
from subiquitycore.lsb_release import lsb_release_from_path
from subiquitycore.tests import SubiTestCase
from subiquitycore.tests.mocks import make_app from subiquitycore.tests.mocks import make_app
from subiquitycore.tests.parameterized import parameterized
class TestUbuntuProController(unittest.TestCase): class TestUbuntuProController(SubiTestCase):
def setUp(self): def setUp(self):
app = make_app() app = make_app()
app.dr_cfg = DRConfig() app.dr_cfg = DRConfig()
@ -45,3 +48,32 @@ class TestUbuntuProController(unittest.TestCase):
) )
JsonValidator.check_schema(UbuntuProController.autoinstall_schema) JsonValidator.check_schema(UbuntuProController.autoinstall_schema)
@parameterized.expand(
[
("focal", 23000, 2300, 2030),
("impish", 23000, 2300, None),
("jammy", 23000, 2300, 2032),
("noble", 23000, 2300, 2034),
]
)
async def test_info_GET__series(
self, series: str, universe_pkgs: int, main_pkgs: int, esm_eol_year: int | None
):
def fake_lsb_release(*args, **kwargs):
return lsb_release_from_path(f"examples/lsb-release-{series}")
with mock.patch(
"subiquity.server.controllers.ubuntu_pro.lsb_release",
wraps=fake_lsb_release,
) as m_lsb_release:
info = await self.controller.info_GET()
m_lsb_release.assert_called_once()
self.assertEqual(universe_pkgs, info.universe_packages)
self.assertEqual(main_pkgs, info.main_packages)
if esm_eol_year is not None:
self.assertEqual(esm_eol_year, info.eol_esm_year)
else:
self.assertIsNone(info.eol_esm_year)

View File

@ -19,10 +19,13 @@ import logging
import os import os
from typing import Optional from typing import Optional
import distro_info
from subiquity.common.apidef import API from subiquity.common.apidef import API
from subiquity.common.types import ( from subiquity.common.types import (
UbuntuProCheckTokenAnswer, UbuntuProCheckTokenAnswer,
UbuntuProCheckTokenStatus, UbuntuProCheckTokenStatus,
UbuntuProGeneralInfo,
UbuntuProInfo, UbuntuProInfo,
UbuntuProResponse, UbuntuProResponse,
UPCSInitiateResponse, UPCSInitiateResponse,
@ -40,6 +43,7 @@ from subiquity.server.ubuntu_advantage import (
UAInterface, UAInterface,
UAInterfaceStrategy, UAInterfaceStrategy,
) )
from subiquitycore.lsb_release import lsb_release
log = logging.getLogger("subiquity.server.controllers.ubuntu_pro") log = logging.getLogger("subiquity.server.controllers.ubuntu_pro")
@ -199,3 +203,27 @@ class UbuntuProController(SubiquityController):
self.cs.cancel() self.cs.cancel()
self.cs = None self.cs = None
async def info_GET(self) -> UbuntuProGeneralInfo:
# Currently the number of packages is hard-coded.
main_packages = 2300
universe_packages = 23000
eol_esm_year: Optional[int] = None
series = lsb_release(dry_run=self.app.opts.dry_run)["codename"]
for release in distro_info.UbuntuDistroInfo()._releases:
if release.series == series:
try:
eol_esm_year = release.eol_esm.year
except AttributeError:
log.warning("series %s does not have an ESM EOL date", series)
break
else:
log.warning("could not find distro info for %s", series)
return UbuntuProGeneralInfo(
eol_esm_year=eol_esm_year,
main_packages=main_packages,
universe_packages=universe_packages,
)