Beispiel #1
0
    def _inject_snap(self, name):
        session = requests_unixsocket.Session()
        # Cf. https://github.com/snapcore/snapd/wiki/REST-API#get-v2snapsname
        # TODO use get_local_snap info from the snaps module.
        slug = 'snaps/{}'.format(parse.quote(name, safe=''))
        api = snaps.get_snapd_socket_path_template().format(slug)
        try:
            json = session.request('GET', api).json()
        except requests.exceptions.ConnectionError as e:
            raise SnapdError(
                'Error connecting to {}'.format(api)) from e
        if json['type'] == 'error':
            raise SnapdError(
                'Error querying {!r} snap: {}'.format(
                    name, json['result']['message']))
        id = json['result']['id']
        # Lookup confinement to know if we need to --classic when installing
        is_classic = json['result']['confinement'] == 'classic'
        # Revisions are unique, so we don't need to know the channel
        rev = json['result']['revision']

        if not rev.startswith('x'):
            self._inject_assertions('{}_{}.assert'.format(name, rev), [
                ['account-key', 'public-key-sha3-384={}'.format(_STORE_KEY)],
                ['snap-declaration', 'snap-name={}'.format(name)],
                ['snap-revision', 'snap-revision={}'.format(rev),
                 'snap-id={}'.format(id)],
            ])

        # https://github.com/snapcore/snapd/blob/master/snap/info.go
        # MountFile
        filename = '{}_{}.snap'.format(name, rev)
        # https://github.com/snapcore/snapd/blob/master/dirs/dirs.go
        # CoreLibExecDir
        installed = os.path.join(os.path.sep, 'var', 'lib', 'snapd', 'snaps',
                                 filename)

        filepath = os.path.join(self.tmp_dir, filename)
        if rev.startswith('x'):
            logger.info('Making {} user-accessible'.format(filename))
            check_call(['sudo', 'cp', installed, filepath])
            check_call(['sudo', 'chown', str(os.getuid()), filepath])
        else:
            shutil.copyfile(installed, filepath)
        container_filename = os.path.join(os.sep, 'run', filename)
        self._push_file(filepath, container_filename)
        logger.info('Installing {}'.format(container_filename))
        cmd = ['snap', 'install', container_filename]
        if rev.startswith('x'):
            cmd.append('--dangerous')
        if is_classic:
            cmd.append('--classic')
        self._container_run(cmd)
Beispiel #2
0
    def _inject_snap(self, name: str, tmp_dir: str):
        session = requests_unixsocket.Session()
        # Cf. https://github.com/snapcore/snapd/wiki/REST-API#get-v2snapsname
        # TODO use get_local_snap info from the snaps module.
        slug = 'snaps/{}'.format(parse.quote(name, safe=''))
        api = snaps.get_snapd_socket_path_template().format(slug)
        try:
            json = session.request('GET', api).json()
        except requests.exceptions.ConnectionError as e:
            raise SnapdError('Error connecting to {}'.format(api)) from e
        if json['type'] == 'error':
            raise SnapdError('Error querying {!r} snap: {}'.format(
                name, json['result']['message']))
        id = json['result']['id']
        # Lookup confinement to know if we need to --classic when installing
        is_classic = json['result']['confinement'] == 'classic'

        # If the server has a different arch we can't inject local snaps
        target_arch = self._project_options.target_arch
        if (target_arch and target_arch != self._get_container_arch()):
            channel = json['result']['channel']
            return self._install_snap(name, channel, is_classic=is_classic)

        # Revisions are unique, so we don't need to know the channel
        rev = json['result']['revision']

        # https://github.com/snapcore/snapd/blob/master/snap/info.go
        # MountFile
        filename = '{}_{}.snap'.format(name, rev)
        # https://github.com/snapcore/snapd/blob/master/dirs/dirs.go
        # CoreLibExecDir
        installed = os.path.join(os.path.sep, 'var', 'lib', 'snapd', 'snaps',
                                 filename)

        filepath = os.path.join(tmp_dir, filename)
        if rev.startswith('x'):
            logger.info('Making {} user-accessible'.format(filename))
            subprocess.check_call(['sudo', 'cp', installed, filepath])
            subprocess.check_call(
                ['sudo', 'chown', str(os.getuid()), filepath])
        else:
            shutil.copyfile(installed, filepath)

        if self._is_same_snap(filepath, name):
            logger.debug('Not re-injecting same version of {!r}'.format(name))
            return

        if not rev.startswith('x'):
            self._inject_assertions('{}_{}.assert'.format(name, rev), [
                ['account-key', 'public-key-sha3-384={}'.format(_STORE_KEY)],
                ['snap-declaration', 'snap-name={}'.format(name)],
                [
                    'snap-revision', 'snap-revision={}'.format(rev),
                    'snap-id={}'.format(id)
                ],
            ], tmp_dir)

        container_filename = os.path.join(os.sep, 'run', filename)
        self._push_file(filepath, container_filename)
        self._install_snap(container_filename,
                           is_dangerous=rev.startswith('x'),
                           is_classic=is_classic)