Merge lp:~sbaldassin/snappy-ecosystem-tests/merge_builder_snapd into lp:snappy-ecosystem-tests

Proposed by Santiago Baldassin
Status: Merged
Approved by: Heber Parrucci
Approved revision: 50
Merged at revision: 49
Proposed branch: lp:~sbaldassin/snappy-ecosystem-tests/merge_builder_snapd
Merge into: lp:snappy-ecosystem-tests
Diff against target: 467 lines (+135/-182)
7 files modified
snappy_ecosystem_tests/helpers/snapcraft/build_snap.py (+0/-161)
snappy_ecosystem_tests/helpers/snapcraft/client.py (+123/-4)
snappy_ecosystem_tests/helpers/snapd/snapd.py (+5/-5)
snappy_ecosystem_tests/helpers/test_base.py (+0/-1)
snappy_ecosystem_tests/tests/test_install_private_snap.py (+2/-7)
snappy_ecosystem_tests/utils/ssh.py (+5/-3)
snappy_ecosystem_tests/utils/user.py (+0/-1)
To merge this branch: bzr merge lp:~sbaldassin/snappy-ecosystem-tests/merge_builder_snapd
Reviewer Review Type Date Requested Status
Heber Parrucci (community) Approve
platform-qa-bot continuous-integration Approve
Review via email: mp+320163@code.launchpad.net

Commit message

Merge Snapcraft and SnapBuilder in a single class

Description of the change

This mp merge Snapcraft and SnapBuilder in a single class as they represent the same class. We'll need to instantiate two different objects, pointing to the builder container and the snapcraft container respectively

To post a comment you must log in.
Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Heber Parrucci (heber013) wrote :

Looks good. One comment inline

review: Needs Fixing
48. By Santiago Baldassin

Addressing comments from the reviews

Revision history for this message
Santiago Baldassin (sbaldassin) wrote :

Thanks Heber. Comments addressed

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Heber Parrucci (heber013) wrote :

There are some tests failing in this branch that pass on trunk, see log http://paste.ubuntu.com/24215045/

Seems that the time between snaps registration is broken.

review: Needs Fixing
49. By Santiago Baldassin

Merge from trunk

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
50. By Santiago Baldassin

Merge from trunk

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Heber Parrucci (heber013) wrote :

Tests are passing properly now http://paste.ubuntu.com/24269814/.
Let's land it.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed file 'snappy_ecosystem_tests/helpers/snapcraft/build_snap.py'
--- snappy_ecosystem_tests/helpers/snapcraft/build_snap.py 2017-03-16 11:40:13 +0000
+++ snappy_ecosystem_tests/helpers/snapcraft/build_snap.py 1970-01-01 00:00:00 +0000
@@ -1,161 +0,0 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2
3#
4# Snappy Ecosystem Tests
5# Copyright (C) 2017 Canonical
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20
21"""Module to build a snap in a remote machine."""
22
23import os
24from pathlib import PurePath
25
26from snappy_ecosystem_tests.utils.ssh import SSHManager
27
28COMMANDS_SETUP = [
29 'apt update',
30 'apt dist-upgrade -y',
31 'apt install snapcraft -y'
32]
33SNAPCRAFT_YAML = """\
34name: {snap_name}
35version: {version}
36summary: {summary}
37description: |
38 {description}
39
40grade: {grade}
41confinement: {confinement}
42
43parts:
44 {snap_name}:
45 plugin: nil
46
47apps:
48 {snap_name}:
49 command: echo ok
50"""
51SUMMARY_SNAP_DEFAULT = 'A test snap.'
52DESCRIPTION_SNAP_DEFAULT = 'A very awesome test snap.'
53GRADE_SNAP_DEFAULT = 'stable'
54CONFINEMENT_SNAP_DEFAULT = 'strict'
55
56
57class SnapBuilder:
58 """Class to build a snap on a remote machine and download its content."""
59 def __init__(self, hostname, username, port=22):
60 self.hostname = hostname
61 self.username = username
62 self.port = port
63
64 @property
65 def ssh(self):
66 """Property tu ensure we get an active connection for every command
67 execution over ssh"""
68 return SSHManager.get_instance(self.hostname, self.username, self.port)
69
70 def run_command_ssh(self, command, cwd=''):
71 """Run command over ssh with optional cwd."""
72 if cwd:
73 command = 'cd {}; {}'.format(cwd, command)
74 return self.ssh.exec_command(command)
75
76 def is_host_setup(self):
77 """Return bool representing whether the remote host is setup by
78 checking if snapcraft package is installed."""
79 try:
80 self.ssh.exec_command('which snapcraft')
81 return True
82 except ValueError:
83 return False
84
85 def setup_host(self):
86 """Setup the host to build a snap, currently only installs
87 snapcraft."""
88 for command in COMMANDS_SETUP:
89 self.ssh.exec_command(command)
90
91 def build(self, name, version, summary=SUMMARY_SNAP_DEFAULT,
92 description=DESCRIPTION_SNAP_DEFAULT, grade=GRADE_SNAP_DEFAULT,
93 confinement=CONFINEMENT_SNAP_DEFAULT):
94 """Build a new snap in the remote host and return its remote path.
95
96 :param name: name of the snap to build.
97 :param version: version number for the snap to build.
98 :param summary: short summary of the snap to build.
99 :param description: long description of the snap.
100 :param grade: stability grade of the snap e.g. stable or devel.
101 :param confinement: confinement policy for the snap e.g.
102 classic, devmode or strict.
103 :raises ValueError: If an error is occurred during snap build.
104 :return: Remote path of the newly build snap package.
105 """
106 if not self.is_host_setup():
107 self.setup_host()
108 tempdir = self.ssh.exec_command('mktemp -d')
109 self.run_command_ssh('mkdir snap', cwd=tempdir)
110 self.run_command_ssh('echo "{}" > snap/snapcraft.yaml'.format(
111 SNAPCRAFT_YAML.format(
112 snap_name=name,
113 version=version,
114 summary=summary,
115 description=description,
116 grade=grade,
117 confinement=confinement
118 )
119 ), cwd=tempdir)
120 self.run_command_ssh('snapcraft', cwd=tempdir)
121 return os.path.join(
122 tempdir,
123 '{name}_{version}_{arch}.snap'.format(
124 name=name,
125 version=version,
126 arch=self.ssh.exec_command('dpkg --print-architecture')
127 )
128 )
129
130 def build_and_pull(self, name, version, summary=SUMMARY_SNAP_DEFAULT,
131 description=DESCRIPTION_SNAP_DEFAULT,
132 grade=GRADE_SNAP_DEFAULT,
133 confinement=CONFINEMENT_SNAP_DEFAULT,
134 output_location='.'):
135 """Build a snap based on the provided arguments and download it.
136
137 :param name: name of the snap to build.
138 :param version: version number for the snap to build.
139 :param summary: short summary of the snap to build.
140 :param description: long description of the snap.
141 :param grade: stability grade of the snap e.g. stable or devel.
142 :param confinement: confinement policy for the snap e.g.
143 classic, devmode or strict.
144 :param output_location: Local location to download the newly built
145 snap to. Defaults to pwd.
146 :raises ValueError: If an error is occurred during snap build.
147 :return: Local path of the newly built and downloaded snap package.
148 """
149 remote_snap_path = self.build(
150 name=name,
151 version=version,
152 summary=summary,
153 description=description,
154 grade=grade,
155 confinement=confinement
156 )
157 output_path_absolute = os.path.abspath(
158 os.path.join(output_location, PurePath(remote_snap_path).name)
159 )
160 self.ssh.pull(remote_snap_path, output_path_absolute)
161 return output_path_absolute
1620
=== modified file 'snappy_ecosystem_tests/helpers/snapcraft/client.py'
--- snappy_ecosystem_tests/helpers/snapcraft/client.py 2017-03-16 16:42:44 +0000
+++ snappy_ecosystem_tests/helpers/snapcraft/client.py 2017-03-22 12:29:23 +0000
@@ -21,9 +21,12 @@
21"""Snapcraft client helpers"""21"""Snapcraft client helpers"""
2222
23import logging23import logging
24import os
24import subprocess25import subprocess
25import time26import time
2627
28from pathlib import PurePath
29
27from snappy_ecosystem_tests.models.snap import Snap30from snappy_ecosystem_tests.models.snap import Snap
28from snappy_ecosystem_tests.utils.commands import build_command31from snappy_ecosystem_tests.utils.commands import build_command
29from snappy_ecosystem_tests.utils.filters import filter_list32from snappy_ecosystem_tests.utils.filters import filter_list
@@ -61,6 +64,34 @@
61SNAPCRAFT_CONFIG_FILE_PATH = '~/.config/snapcraft/snapcraft.cfg'64SNAPCRAFT_CONFIG_FILE_PATH = '~/.config/snapcraft/snapcraft.cfg'
6265
6366
67COMMANDS_SETUP = [
68 'apt update',
69 'apt dist-upgrade -y',
70 'apt install snapcraft -y'
71]
72SNAPCRAFT_YAML = """\
73name: {snap_name}
74version: {version}
75summary: {summary}
76description: |
77 {description}
78
79grade: {grade}
80confinement: {confinement}
81
82parts:
83 {snap_name}:
84 plugin: nil
85
86apps:
87 {snap_name}:
88 command: echo ok
89"""
90SUMMARY_SNAP_DEFAULT = 'A test snap.'
91DESCRIPTION_SNAP_DEFAULT = 'A very awesome test snap.'
92GRADE_SNAP_DEFAULT = 'stable'
93CONFINEMENT_SNAP_DEFAULT = 'strict'
94
64class Snapcraft:95class Snapcraft:
65 """Contain Snapcraft specific functionality to use via command96 """Contain Snapcraft specific functionality to use via command
66 line interface"""97 line interface"""
@@ -75,7 +106,22 @@
75 execution over ssh"""106 execution over ssh"""
76 return SSHManager.get_instance(HOSTNAME, USERNAME, PORT)107 return SSHManager.get_instance(HOSTNAME, USERNAME, PORT)
77108
78 def _run_snapcraft_command_ssh(self, command, debug=True):109 def is_host_setup(self):
110 """Return bool representing whether the remote host is setup by
111 checking if snapcraft package is installed."""
112 try:
113 self.ssh.run_command('which snapcraft')
114 return True
115 except ValueError:
116 return False
117
118 def setup_host(self):
119 """Setup the host to build a snap, currently only installs
120 snapcraft."""
121 for command in COMMANDS_SETUP:
122 self.ssh.run_command(command)
123
124 def _run_snapcraft_command_ssh(self, command='', debug=True, cwd=''):
79 """125 """
80 Run snapcraft command via ssh126 Run snapcraft command via ssh
81 :param command: the command to be executed.127 :param command: the command to be executed.
@@ -87,7 +133,7 @@
87 command = build_snapcraft_command(command)133 command = build_snapcraft_command(command)
88 if debug:134 if debug:
89 command += ' -d'135 command += ' -d'
90 return self.ssh.exec_command(command)136 return self.ssh.run_command(command, cwd=cwd)
91137
92 def assert_logged_in(self):138 def assert_logged_in(self):
93 """Assert that an user is logged.139 """Assert that an user is logged.
@@ -100,7 +146,7 @@
100 def is_logged_in(self):146 def is_logged_in(self):
101 """Return bool representing if the user is logged into snapcraft."""147 """Return bool representing if the user is logged into snapcraft."""
102 try:148 try:
103 output = self.ssh.exec_command(149 output = self.ssh.run_command(
104 'cat %s' % SNAPCRAFT_CONFIG_FILE_PATH)150 'cat %s' % SNAPCRAFT_CONFIG_FILE_PATH)
105 return output is not ''151 return output is not ''
106 except ValueError:152 except ValueError:
@@ -123,7 +169,7 @@
123 :param email: the SSO email169 :param email: the SSO email
124 :param password: the email password170 :param password: the email password
125 """171 """
126 self.ssh.exec_command(172 self.ssh.run_command(
127 COMMANDS_LOGIN.format(email=email, password=password,173 COMMANDS_LOGIN.format(email=email, password=password,
128 snapcraft=PATH_SNAPCRAFT))174 snapcraft=PATH_SNAPCRAFT))
129 return self.is_logged_in()175 return self.is_logged_in()
@@ -185,6 +231,79 @@
185 LOGGER.info('Snap %s registered successfully!!!', snap_name)231 LOGGER.info('Snap %s registered successfully!!!', snap_name)
186 return True232 return True
187233
234 def build(self, name, version, summary=SUMMARY_SNAP_DEFAULT,
235 description=DESCRIPTION_SNAP_DEFAULT, grade=GRADE_SNAP_DEFAULT,
236 confinement=CONFINEMENT_SNAP_DEFAULT):
237 """Build a new snap in the remote host and return its remote path.
238
239 :param name: name of the snap to build.
240 :param version: version number for the snap to build.
241 :param summary: short summary of the snap to build.
242 :param description: long description of the snap.
243 :param grade: stability grade of the snap e.g. stable or devel.
244 :param confinement: confinement policy for the snap e.g.
245 classic, devmode or strict.
246 :raises ValueError: If an error is occurred during snap build.
247 :return: Remote path of the newly build snap package.
248 """
249 if not self.is_host_setup():
250 self.setup_host()
251 tempdir = self.ssh.run_command('mktemp -d')
252 self.ssh.run_command('mkdir snap', cwd=tempdir)
253 self.ssh.run_command(
254 'echo "{}" > snap/snapcraft.yaml'.format(
255 SNAPCRAFT_YAML.format(
256 snap_name=name,
257 version=version,
258 summary=summary,
259 description=description,
260 grade=grade,
261 confinement=confinement
262 )
263 ), cwd=tempdir)
264 self._run_snapcraft_command_ssh(cwd=tempdir)
265 return os.path.join(
266 tempdir,
267 '{name}_{version}_{arch}.snap'.format(
268 name=name,
269 version=version,
270 arch=self.ssh.run_command('dpkg --print-architecture')
271 )
272 )
273
274 def build_and_pull(self, name, version, summary=SUMMARY_SNAP_DEFAULT,
275 description=DESCRIPTION_SNAP_DEFAULT,
276 grade=GRADE_SNAP_DEFAULT,
277 confinement=CONFINEMENT_SNAP_DEFAULT,
278 output_location='.'):
279 """Build a snap based on the provided arguments and download it.
280
281 :param name: name of the snap to build.
282 :param version: version number for the snap to build.
283 :param summary: short summary of the snap to build.
284 :param description: long description of the snap.
285 :param grade: stability grade of the snap e.g. stable or devel.
286 :param confinement: confinement policy for the snap e.g.
287 classic, devmode or strict.
288 :param output_location: Local location to download the newly built
289 snap to. Defaults to pwd.
290 :raises ValueError: If an error is occurred during snap build.
291 :return: Local path of the newly built and downloaded snap package.
292 """
293 remote_snap_path = self.build(
294 name=name,
295 version=version,
296 summary=summary,
297 description=description,
298 grade=grade,
299 confinement=confinement
300 )
301 output_path_absolute = os.path.abspath(
302 os.path.join(output_location, PurePath(remote_snap_path).name)
303 )
304 self.ssh.pull(remote_snap_path, output_path_absolute)
305 return output_path_absolute
306
188307
189def build_snapcraft_command(*args, base_command=PATH_SNAPCRAFT):308def build_snapcraft_command(*args, base_command=PATH_SNAPCRAFT):
190 """309 """
191310
=== modified file 'snappy_ecosystem_tests/helpers/snapd/snapd.py'
--- snappy_ecosystem_tests/helpers/snapd/snapd.py 2017-03-19 15:27:11 +0000
+++ snappy_ecosystem_tests/helpers/snapd/snapd.py 2017-03-22 12:29:23 +0000
@@ -74,7 +74,7 @@
74 command = '{} {}'.format(PATH_SNAP, command)74 command = '{} {}'.format(PATH_SNAP, command)
75 if cwd:75 if cwd:
76 command = '{}; {}'.format(cwd, command)76 command = '{}; {}'.format(cwd, command)
77 return self.ssh.exec_command(command)77 return self.ssh.run_command(command)
7878
79 def login(self, email, password):79 def login(self, email, password):
80 """Login to snapd.80 """Login to snapd.
@@ -82,15 +82,15 @@
82 :param email: Ubuntu SSO account email address.82 :param email: Ubuntu SSO account email address.
83 :param password: Ubuntu SSO account password.83 :param password: Ubuntu SSO account password.
84 """84 """
85 self.ssh.exec_command(COMMANDS_LOGIN.format(email=email,85 self.ssh.run_command(COMMANDS_LOGIN.format(email=email,
86 password=password))86 password=password))
87 return self.is_logged_in(email)87 return self.is_logged_in(email)
8888
89 def is_logged_in(self, email):89 def is_logged_in(self, email):
90 """Return bool representing if the user is logged into snapd."""90 """Return bool representing if the user is logged into snapd."""
91 try:91 try:
92 return json.loads(92 return json.loads(
93 self.ssh.exec_command(93 self.ssh.run_command(
94 'cat ~/.snap/auth.json')).get('email') == email94 'cat ~/.snap/auth.json')).get('email') == email
95 except ValueError:95 except ValueError:
96 return False96 return False
@@ -108,7 +108,7 @@
108 """108 """
109 command = COMMAND_DOWNLOAD.format(snap=snap, channel=channel)109 command = COMMAND_DOWNLOAD.format(snap=snap, channel=channel)
110 self.run_snapd_command_ssh(command,110 self.run_snapd_command_ssh(command,
111 cwd=self.ssh.exec_command('mktemp -d'))111 cwd=self.ssh.run_command('mktemp -d'))
112112
113 def install(self, snap, channel=CHANNEL_STABLE):113 def install(self, snap, channel=CHANNEL_STABLE):
114 """Install the requested snap."""114 """Install the requested snap."""
115115
=== modified file 'snappy_ecosystem_tests/helpers/test_base.py'
--- snappy_ecosystem_tests/helpers/test_base.py 2017-03-08 17:29:20 +0000
+++ snappy_ecosystem_tests/helpers/test_base.py 2017-03-22 12:29:23 +0000
@@ -15,7 +15,6 @@
15# along with this program. If not, see <http://www.gnu.org/licenses/>.15# along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
17"""Base Snappy Ecosystem test"""17"""Base Snappy Ecosystem test"""
18
19import testscenarios18import testscenarios
20import testtools19import testtools
2120
2221
=== modified file 'snappy_ecosystem_tests/tests/test_install_private_snap.py'
--- snappy_ecosystem_tests/tests/test_install_private_snap.py 2017-03-17 20:50:55 +0000
+++ snappy_ecosystem_tests/tests/test_install_private_snap.py 2017-03-22 12:29:23 +0000
@@ -19,16 +19,12 @@
19#19#
2020
21"""Tests for Installing private snaps."""21"""Tests for Installing private snaps."""
2222from snappy_ecosystem_tests.helpers.snapcraft.client import Snapcraft
23from snappy_ecosystem_tests.helpers.snapd.snapd import Snapd23from snappy_ecosystem_tests.helpers.snapd.snapd import Snapd
24from snappy_ecosystem_tests.helpers.store_apis.rest_apis import Store24from snappy_ecosystem_tests.helpers.store_apis.rest_apis import Store
25from snappy_ecosystem_tests.helpers.snapcraft.build_snap import SnapBuilder
26from snappy_ecosystem_tests.helpers.test_base import SnappyEcosystemTestCase25from snappy_ecosystem_tests.helpers.test_base import SnappyEcosystemTestCase
27from snappy_ecosystem_tests.tests.commons import get_random_snap_name26from snappy_ecosystem_tests.tests.commons import get_random_snap_name
28from snappy_ecosystem_tests.utils.storeconfig import get_store_credentials27from snappy_ecosystem_tests.utils.storeconfig import get_store_credentials
29from snappy_ecosystem_tests.utils.user import (
30 get_snapcraft_remote_host_credentials
31)
3228
3329
34class RegisterInstallPrivateSnapTestCase(SnappyEcosystemTestCase):30class RegisterInstallPrivateSnapTestCase(SnappyEcosystemTestCase):
@@ -42,8 +38,7 @@
42 self.addCleanup(self.snapd.logout, email)38 self.addCleanup(self.snapd.logout, email)
43 self.store.login(email, password)39 self.store.login(email, password)
44 self.addCleanup(self.store.logout)40 self.addCleanup(self.store.logout)
45 self.snap_builder = SnapBuilder(41 self.snap_builder = Snapcraft()
46 *get_snapcraft_remote_host_credentials())
4742
48 def test_upload_and_install_private_snap(self):43 def test_upload_and_install_private_snap(self):
49 """Test to register and upload a private snap via the REST API44 """Test to register and upload a private snap via the REST API
5045
=== modified file 'snappy_ecosystem_tests/utils/ssh.py'
--- snappy_ecosystem_tests/utils/ssh.py 2017-03-09 17:24:06 +0000
+++ snappy_ecosystem_tests/utils/ssh.py 2017-03-22 12:29:23 +0000
@@ -30,12 +30,14 @@
30class SSHClient(paramiko.SSHClient):30class SSHClient(paramiko.SSHClient):
31 """Extended SSHClient."""31 """Extended SSHClient."""
3232
33 def exec_command(self, command, bufsize=-1, timeout=None, get_pty=False,33 def run_command(self, command, bufsize=-1, timeout=None,
34 environment=None):34 get_pty=False, cwd=''):
35 """Execute the given command over ssh."""35 """Execute the given command over ssh."""
36 if cwd:
37 command = 'cd {}; {}'.format(cwd, command)
36 _, stdout, stderr = super().exec_command(38 _, stdout, stderr = super().exec_command(
37 command, bufsize, timeout,39 command, bufsize, timeout,
38 get_pty, environment=environment)40 get_pty)
39 if stdout.channel.recv_exit_status() != 0:41 if stdout.channel.recv_exit_status() != 0:
40 raise ValueError(stderr.read().decode().strip())42 raise ValueError(stderr.read().decode().strip())
41 response = stdout.read().decode().strip()43 response = stdout.read().decode().strip()
4244
=== modified file 'snappy_ecosystem_tests/utils/user.py'
--- snappy_ecosystem_tests/utils/user.py 2017-03-09 10:41:13 +0000
+++ snappy_ecosystem_tests/utils/user.py 2017-03-22 12:29:23 +0000
@@ -27,7 +27,6 @@
2727
28MANAGER = get_manager(os.environ['target'])28MANAGER = get_manager(os.environ['target'])
2929
30
31def get_snapd_remote_host_credentials():30def get_snapd_remote_host_credentials():
32 """Return credentials for snapd remote machine, to run commands on."""31 """Return credentials for snapd remote machine, to run commands on."""
33 _ip = MANAGER.driver.get_ip(USER_CONFIG_STACK.get(32 _ip = MANAGER.driver.get_ip(USER_CONFIG_STACK.get(

Subscribers

People subscribed via source and target branches

to all changes: