[kteam-tools][PATCH 4/5] wfl: add a helper class for snap store

Kleber Sacilotto de Souza kleber.souza at canonical.com
Fri Nov 10 08:18:16 UTC 2017


Add a helper class to handle the snap store operations. For now it loads
the versioning info for a snap associated with a tracking bug on first
use and provides a method to check if the kernel package version matches
the snap version for a given channel.

Signed-off-by: Kleber Sacilotto de Souza <kleber.souza at canonical.com>
---
 stable/wfl/snap.py | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)
 create mode 100644 stable/wfl/snap.py

diff --git a/stable/wfl/snap.py b/stable/wfl/snap.py
new file mode 100644
index 00000000..7afcbf76
--- /dev/null
+++ b/stable/wfl/snap.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+
+try:
+    from urllib.request import urlopen, Request
+    from urllib.parse import urlencode, urljoin
+    from urllib.error import URLError, HTTPError
+except ImportError:
+    from urllib2 import urlopen, urlencode, Request, URLError, HTTPError
+
+import json
+from .errors import ShankError
+
+
+# SnapStoreError
+#
+class SnapStoreError(ShankError):
+    """
+    Thrown when something goes wrong with the snap store (e.g. snap not found).
+    """
+    def __init__(s, emsg):
+        super(SnapStoreError, s).__init__(emsg)
+
+    def __str__(s):
+        return s.message
+
+
+# SnapStore
+#
+class SnapStore:
+    """
+    A helper class to handle Snapcraft store operations.
+    """
+    base_url = "https://search.apps.ubuntu.com/api/v1/snaps/details/"
+    common_headers = {'X-Ubuntu-Series': '16'}
+
+    # __init__
+    #
+    def __init__(s, bug):
+        """
+        :param bug: WorkflowBug object
+        """
+        s.bug = bug
+        s._dependent_snap = None
+        s._snap_store_versions = {}  # dictionary with {<channel>: {<arch>: <version>[, ...]}[, ...]}
+
+    # _get_snap_info
+    #
+    def _get_snap_info(s, channel):
+        """
+        Query the snap store URL to get the information about the kernel snap
+        on the provided channel and store it in the private variables.
+
+        :return: nothing
+        """
+        if s._dependent_snap is None:
+            try:
+                record = s.bug.ubuntu.lookup(s.bug.series)
+                s._dependent_snap = record['dependent-snaps'][s.bug.pkg_name]
+            except KeyError:
+                raise SnapStoreError('Could not find snap for series/package \'%s/%s\'' %
+                                     (s.bug.series, s.bug.pkg_name))
+
+        s._snap_store_versions[channel] = {}
+        for arch in s._dependent_snap['arches']:
+            try:
+                headers = s.common_headers
+                headers['X-Ubuntu-Architecture'] = arch
+                params = urlencode({'fields': 'version', 'channel': channel})
+                url = "%s?%s" % (urljoin(s.base_url, s._dependent_snap['snap']), params)
+                req = Request(url, headers=headers)
+                with urlopen(req) as resp:
+                    version = json.loads(resp.read())['version']
+                    s._snap_store_versions[channel][arch] = version
+            except HTTPError as e:
+                # Error 404 is returned if the snap has never been published
+                # to the given channel.
+                store_err = False
+                if hasattr(e, 'code') and e.code == 404:
+                    ret_body = e.read().decode()
+                    store_err_str = 'has no published revisions in the given context'
+                    if store_err_str in ret_body:
+                        store_err = True
+                        s._snap_store_versions[channel][arch] = None
+                if not store_err:
+                    raise SnapStoreError('failed to retrieve store URL (%s)' % str(e))
+            except (URLError, KeyError) as e:
+                raise SnapStoreError('failed to retrieve store URL (%s: %s)' %
+                                     (type(e), str(e)))
+
+    # match_version
+    #
+    def match_version(s, channel):
+        """
+        Check if the snap version on the store for the given channel corresponds
+        to the kernel version and abi numbers of the kernel package.
+
+        :param channel: store channel name
+        :return: True if the snap version for all arches on the given channel match the
+        kernel version and ABI from the tracking bug, False otherwise
+        """
+
+        try:
+            s._get_snap_info(channel)
+        except:
+            raise
+
+        # Loop over the store version for all arches and check if they are consistent.
+        store_version = None
+        for arch in s._snap_store_versions[channel].keys():
+            if s._snap_store_versions[channel][arch] is None:
+                # Return False if there are no published version for one of the arches
+                return False
+            if store_version is None:
+                store_version = s._snap_store_versions[channel][arch]
+            elif store_version != s._snap_store_versions[channel][arch]:
+                return False
+
+        return (store_version is not None and
+                store_version.rpartition('.')[0] == "%s.%s" % (s.bug.kernel_version, s.bug.abi))
-- 
2.14.1





More information about the kernel-team mailing list