Merge lp:~canonical-platform-qa/snappy-ecosystem-tests/helpers_for_snapd_cli into lp:snappy-ecosystem-tests

Proposed by Omer Akram
Status: Merged
Approved by: Heber Parrucci
Approved revision: 37
Merged at revision: 23
Proposed branch: lp:~canonical-platform-qa/snappy-ecosystem-tests/helpers_for_snapd_cli
Merge into: lp:snappy-ecosystem-tests
Prerequisite: lp:~canonical-platform-qa/snappy-ecosystem-tests/minor_tweaks
Diff against target: 359 lines (+314/-0)
6 files modified
README.rst (+6/-0)
requirements.txt (+2/-0)
snappy_ecosystem_tests/helpers/snapd/snapd.py (+137/-0)
snappy_ecosystem_tests/tests/test_snapd.py (+42/-0)
snappy_ecosystem_tests/utils/ssh.py (+92/-0)
snappy_ecosystem_tests/utils/user.py (+35/-0)
To merge this branch: bzr merge lp:~canonical-platform-qa/snappy-ecosystem-tests/helpers_for_snapd_cli
Reviewer Review Type Date Requested Status
Heber Parrucci (community) Approve
Santiago Baldassin (community) Approve
platform-qa-bot continuous-integration Approve
I Ahmad (community) Needs Fixing
Review via email: mp+316459@code.launchpad.net

Commit message

Basic helpers around snapd' command line interface

Description of the change

Basic helpers around snapd' command line interface

To post a comment you must log in.
Revision history for this message
I Ahmad (iahmad) wrote :

Please see my inline comments

review: Needs Fixing
Revision history for this message
I Ahmad (iahmad) :
8. By Omer Akram

merge with trunk

9. By Omer Akram

Assert when logged in

Revision history for this message
Omer Akram (om26er) wrote :

Replied inline.

10. By Omer Akram

fix login command

Revision history for this message
I Ahmad (iahmad) wrote :
Download full text (7.7 KiB)

I am fine as long as data is not parsed/filtered within helper method

On Tue, Feb 7, 2017 at 7:48 PM, Omer Akram <email address hidden> wrote:

> Replied inline.
>
> Diff comments:
>
> >
> > === modified file 'tests/utils/snapd.py'
> > --- tests/utils/snapd.py 2017-02-06 14:05:03 +0000
> > +++ tests/utils/snapd.py 2017-02-06 14:05:03 +0000
> > @@ -17,3 +17,138 @@
> > # You should have received a copy of the GNU General Public License
> > # along with this program. If not, see <http://www.gnu.org/licenses/>.
> > #
> > +
> > +import getpass
> > +import os
> > +import subprocess
> > +import sys
> > +import shlex
> > +import shutil
> > +import tempfile
> > +
> > +import pexpect
> > +import yaml
> > +
> > +PATH_SNAP = '/usr/bin/snap'
> > +COMMAND_DOWNLOAD = 'download {snap} --channel={channel}'
> > +COMMAND_FIND = 'find {search_term}'
> > +COMMAND_INFO = 'info {snap}'
> > +COMMAND_INSTALL = 'install {snap} --channel={channel}'
> > +COMMAND_LOGIN = 'login {email}'
> > +COMMAND_LOGOUT = 'logout'
> > +COMMAND_REFRESH = 'refresh {snap} --channel={channel}'
> > +CHANNEL_STABLE = 'stable'
> > +PASSWORD_ROOT = 'changed'
> > +
> > +
> > +def is_root_user():
> > + """Return bool representing if the current user is root."""
> > + return os.getuid() == 0
> > +
> > +
> > +def run_snapd_command(parameters, return_output=False, cwd=None):
> > + """ Run the request snapd cli command.
> > +
> > + :param parameters: the snapd sub-command and their parameters.
> > + example: install core --beta
> > + :param return_output: Whether to return the stdout of the command.
> > + :param cwd: The current working directory for the command, defaults
> to
> > + pwd.
> > + :return: Optionally return the stdout of the command, depending if
> > + the value of `return_output` was True.
> > + """
> > + command = '{} {}'.format(PATH_SNAP, parameters)
> > + if return_output:
> > + raw_output = subprocess.check_output(
> > + shlex.split(command), universal_newlines=True, cwd=cwd)
> > + return raw_output.strip().split('\n')
> > + subprocess.check_call(shlex.split(command), cwd=cwd)
> > +
> > +
> > +def login(email, password):
> > + """Login to snapd.
> > +
> > + :param email: Ubuntu SSO account email address.
> > + :param password: Ubuntu SSO account password.
> > + """
> > + command = '{} {}'.format(COMMAND_LOGIN, email)
> > + if is_root_user():
> > + p = pexpect.spawnu(command, logfile=sys.stdout)
> > + else:
> > + p = pexpect.spawnu('{} {}'.format('sudo', command),
> logfile=sys.stdout)
> > + p.expect_exact(
> > + '[sudo] password for {}: '.format(getpass.getuser()))
> > + p.sendline(PASSWORD_ROOT)
> > + p.expect_exact('Password of "{}": '.format(email))
> > + p.sendline(password)
> > + p.wait()
> > +
>
> I added an assert to ensure the login was successful.
>
> > +
> > +def logout():
> > + run_snapd_command(COMMAND_LOGOUT)
> > +
> > +
> > +def download(snap, channel=CHANNEL_STABLE, path=None):
> > + """Download the requested snap.
> > +
> > + :param snap: name of the snap to download.
> > + :param channel:...

Read more...

11. By Omer Akram

Simplify .
./snapd.py
./snapcraft.py
./__pycache__
./__pycache__/snapd.cpython-35.pyc
./__init__.py method to remove client side filtering

Revision history for this message
Omer Akram (om26er) wrote :

Ok, removed the filtering code now.

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
12. By Omer Akram

Merge with trunk

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Omer Akram (om26er) wrote :

I have made the suggested changes.

13. By Omer Akram

Fix pylint complaints

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
14. By Omer Akram

add fixme comment

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
15. By Omer Akram

more compact code. always return command output

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 in general. Couple of comments inline. Additionally:

* Merge from trunk
* Can you add a single test that checks if it is possible to login in snapd? in /tests folder
* Can you move snapd.py from utils to helpers?

review: Needs Fixing
16. By Omer Akram

revert

17. By Omer Akram

merge with trunk

18. By Omer Akram

bring back changes

19. By Omer Akram

read password from config, other changes

20. By Omer Akram

add simple test case for snapd

Revision history for this message
Omer Akram (om26er) wrote :

Replied inline also added a few simple test cases.

Revision history for this message
Heber Parrucci (heber013) wrote :

Looks good. One comment inline

review: Needs Fixing
Revision history for this message
Omer Akram (om26er) wrote :

sure, let me fix that.

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
21. By Omer Akram

Update snapd helpers to execute over ssh

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
22. By Omer Akram

Merge with trunk

23. By Omer Akram

pylint happy

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Omer Akram (om26er) wrote :

I updated this branch to execute all commands over ssh. With paramiko we automagically get a persistent ssh connection, so the performance should not be a problem. The remote machine should have `expect` installed. Both snapd and snapcraft commands should work just fine over ssh. For store api calls, we need a small wrapper that builds curl commands based on our requirements to be run over ssh.

with that we can have a single way to run tests on all targets (kvm, bare metal, all-snap(in future), lxd or a tablet.)

TODO: run_command_over_ssh need to be changed to actually utilize connection persistence advantages of paramiko, but I wanted to check how we all think about this direction.

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

Looks good. Just minor comments

review: Needs Fixing
24. By Omer Akram

Maintain persistent ssh object, fix review comments

25. By Omer Akram

rename and move ssh runner function to ssh.py

Revision history for this message
Omer Akram (om26er) wrote :

Replied inline.

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
26. By Omer Akram

More readable calls

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
27. By Omer Akram

fix some words

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
28. By Omer Akram

ignore chrome driver from requirements

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

Looks good but I think the ssh approach does not entirely solve the issue we discussed. See inline

review: Needs Fixing
Revision history for this message
Omer Akram (om26er) wrote :

Added a comment.

Revision history for this message
Omer Akram (om26er) wrote :

Adding slightly less relevant comment.

29. By Omer Akram

Add protection against direct initialization of SSHClient

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Needs Fixing (continuous-integration)
30. By Omer Akram

Merge with 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 :

See comments inline.

review: Needs Fixing
31. By Omer Akram

Add optional overriding of hostname and username to run commands

Revision history for this message
Omer Akram (om26er) wrote :

Replied inline, also extended run_command to optionally take hostname and username as suggested in your code.

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

Reply inline. Let's talk about this over the phone before we get into an endless discussion

review: Needs Fixing
Revision history for this message
Omer Akram (om26er) wrote :

Replied and lets chat.

Revision history for this message
Heber Parrucci (heber013) wrote :

Reply inline. Let's talk offline

Revision history for this message
Sergio Cazzolato (sergio-j-cazzolato) wrote :

Comment inline

32. By Omer Akram

Update to a SSHManager approach to keep a pool of active connections

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Omer Akram (om26er) wrote :

Replied inline.

33. By Omer Akram

Add doc-string

Revision history for this message
Omer Akram (om26er) wrote :

Sergio, replied inline.

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
34. By Omer Akram

More simpler and compact approach

Revision history for this message
platform-qa-bot (platform-qa-bot) wrote :
review: Approve (continuous-integration)
35. By Omer Akram

reuse some code

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 much better. Just a question inline.
Additionally, can you update README with remote host credentials info? you can reuse User Credentials section in that file if you wish.

36. By Omer Akram

update README for ssh credentials

Revision history for this message
Omer Akram (om26er) wrote :

Updated README, added inline comments.

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

Looks good. Minor comments inline

Revision history for this message
Heber Parrucci (heber013) wrote :

Reply to Santiago's suggestion

Revision history for this message
Omer Akram (om26er) wrote :

Replied.

Revision history for this message
Omer Akram (om26er) wrote :

re.

37. By Omer Akram

Changes

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

Looks Good. Thanks

review: Approve
Revision history for this message
Heber Parrucci (heber013) wrote :

Code LGTM. Let's land it.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'README.rst'
--- README.rst 2017-02-20 22:56:17 +0000
+++ README.rst 2017-02-22 19:08:43 +0000
@@ -69,10 +69,16 @@
69[user]69[user]
70user_email=^USER_NAME^70user_email=^USER_NAME^
71user_password=^USER_PASSWORD^71user_password=^USER_PASSWORD^
72hostname_remote=^SSH_HOSTNAME^
73username_remote=^SSH_USERNAME^
74port_remote=^SSH_PORT^
7275
73option 2 - Set the following environment variables:76option 2 - Set the following environment variables:
74user_email=^USER_NAME^77user_email=^USER_NAME^
75user_password=^USER_PASSWORD^78user_password=^USER_PASSWORD^
79hostname_remote=^SSH_HOSTNAME^
80username_remote=^SSH_USERNAME^
81port_remote=^SSH_PORT^
7682
7783
78Changing store:84Changing store:
7985
=== modified file 'requirements.txt'
--- requirements.txt 2017-02-21 12:00:19 +0000
+++ requirements.txt 2017-02-22 19:08:43 +0000
@@ -16,3 +16,5 @@
16requests-toolbelt==0.6.016requests-toolbelt==0.6.0
17#chromedriver_installer17#chromedriver_installer
18pylxd18pylxd
19pyyaml
20paramiko
1921
=== modified file 'snappy_ecosystem_tests/helpers/snapd/snapd.py'
--- snappy_ecosystem_tests/helpers/snapd/snapd.py 2017-02-09 20:09:40 +0000
+++ snappy_ecosystem_tests/helpers/snapd/snapd.py 2017-02-22 19:08:43 +0000
@@ -17,3 +17,140 @@
17# You should have received a copy of the GNU General Public License17# 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/>.18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#19#
20
21"""Helpers around snapd command-line interface."""
22
23import json
24import logging
25
26import yaml
27
28from snappy_ecosystem_tests.utils import ssh
29
30PATH_SNAP = '/usr/bin/snap'
31COMMAND_DOWNLOAD = 'download {snap} --channel={channel}'
32COMMAND_FIND = 'find {search_term}'
33COMMAND_INFO = 'info {snap}'
34COMMAND_INSTALL = 'install {snap} --channel={channel}'
35COMMAND_LIST = 'list'
36COMMAND_LOGIN = 'login {email}'
37COMMAND_LOGOUT = 'logout'
38COMMAND_REFRESH = 'refresh {snap} --channel={channel}'
39COMMAND_REMOVE = 'remove {snap}'
40CHANNEL_STABLE = 'stable'
41COMMANDS_LOGIN = """\
42/usr/bin/expect \
43-c 'spawn snap login {email}' \
44-c 'expect \"Password*\"' \
45-c 'send {password}\\r' \
46-c 'interact'\
47"""
48LOGGER = logging.getLogger(__name__)
49
50
51def run_snapd_command_ssh(parameters, cwd=''):
52 """Run snapd command over ssh.
53
54 :param parameters: a string containing parameters for the `snap` command.
55 :param cwd: the current working directory on the remote where the command
56 should run.
57 :returns: stdout of the command
58 """
59 if cwd:
60 return ssh.run_command(
61 'cd {}; {} {}'.format(cwd, PATH_SNAP, parameters))
62 return ssh.run_command('{} {}'.format(PATH_SNAP, parameters))
63
64
65def login(email, password):
66 """Login to snapd.
67
68 :param email: Ubuntu SSO account email address.
69 :param password: Ubuntu SSO account password.
70 """
71 ssh.run_command(COMMANDS_LOGIN.format(email=email, password=password))
72 return is_logged_in(email)
73
74
75def is_logged_in(email):
76 """Return bool representing if the user is logged into snapd."""
77 try:
78 return json.loads(ssh.run_command('cat ~/.snap/auth.json')).get(
79 'email') == email
80 except ValueError:
81 return False
82
83
84def logout(email):
85 """Logout snapd current user."""
86 if is_logged_in(email):
87 run_snapd_command_ssh(COMMAND_LOGOUT)
88
89
90def download(snap, channel=CHANNEL_STABLE):
91 """Download the requested snap.
92
93 :param snap: name of the snap to download.
94 :param channel: name of the release channel to download from.
95 """
96 command = COMMAND_DOWNLOAD.format(snap=snap, channel=channel)
97 run_snapd_command_ssh(command, cwd=ssh.run_command('mktemp -d'))
98
99
100def install(snap, channel=CHANNEL_STABLE):
101 """Install the requested snap."""
102 run_snapd_command_ssh(COMMAND_INSTALL.format(snap=snap, channel=channel))
103
104
105def _is_installed(snap):
106 """Return bool representing whether a snap is installed."""
107 for installed_snap in _parse_output(run_snapd_command_ssh(COMMAND_LIST)):
108 if installed_snap['name'] == snap:
109 return True
110 return False
111
112
113def remove(snap):
114 """Remove a snap, if its already installed."""
115 if _is_installed(snap):
116 run_snapd_command_ssh(COMMAND_REMOVE.format(snap=snap))
117
118
119def info(snap, verbose=False):
120 """Query the Ubuntu store of the information about a snap.
121
122 :param snap: Name of the snap for which the info is required.
123 :param verbose: Whether to information should be detailed.
124 :return: Return a dictionary containing information about the snap.
125 """
126 command = COMMAND_INFO.format(snap=snap)
127 if verbose:
128 command = ' '.join([command, '--verbose'])
129 return yaml.load("""{}""".format(run_snapd_command_ssh(command)))
130
131
132def refresh(snap, channel=CHANNEL_STABLE):
133 """Refresh the requested snap."""
134 run_snapd_command_ssh(COMMAND_REFRESH.format(snap=snap, channel=channel))
135
136
137def _parse_output(raw_output):
138 """Pretty parse the output from snapd commands like `find` and `list`.
139
140 :param raw_output: The raw output returned from the command
141 :return: A list of dictionaries containing sorted results from the output.
142 """
143 split_output = raw_output.split('\n')
144 headers = [header.lower() for header in split_output.pop(0).split()]
145 return [dict(zip(headers, line.split())) for line in split_output]
146
147
148def find(keyword):
149 """Find snaps based on the provided filters
150
151 :param keyword: Keyword to use for the query.
152 :return: Return a list of dictionaries containing information about
153 snaps matching the `keyword`.
154 """
155 return _parse_output(
156 run_snapd_command_ssh(COMMAND_FIND.format(search_term=keyword)))
20157
=== added file 'snappy_ecosystem_tests/tests/test_snapd.py'
--- snappy_ecosystem_tests/tests/test_snapd.py 1970-01-01 00:00:00 +0000
+++ snappy_ecosystem_tests/tests/test_snapd.py 2017-02-22 19:08:43 +0000
@@ -0,0 +1,42 @@
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"""Snapd testcases."""
22
23import testtools
24
25from snappy_ecosystem_tests.helpers.snapd import snapd
26from snappy_ecosystem_tests.utils.storeconfig import get_store_credentials
27
28
29class SnapdTestCase(testtools.TestCase):
30 """Tests for snapd."""
31 def setUp(self):
32 super().setUp()
33
34 def test_info(self):
35 """Ensure the publisher of core snap in canonical."""
36 self.assertTrue('canonical', snapd.info('core')['publisher'])
37
38 def test_login(self):
39 """Login the snapd user."""
40 email, password = get_store_credentials()
41 self.assertTrue(snapd.login(email, password))
42 self.addCleanup(snapd.logout, email)
043
=== added file 'snappy_ecosystem_tests/utils/ssh.py'
--- snappy_ecosystem_tests/utils/ssh.py 1970-01-01 00:00:00 +0000
+++ snappy_ecosystem_tests/utils/ssh.py 2017-02-22 19:08:43 +0000
@@ -0,0 +1,92 @@
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 connect to ssh client for running tests."""
22
23import paramiko
24
25from snappy_ecosystem_tests.utils.user import get_remote_host_credentials
26
27
28class SSHManager:
29 """Manager class to keep a pool of ssh connections."""
30 # Mangle the pool so that it cannot be easily touched from outside.
31 __connection_pool = []
32
33 def __init__(self):
34 raise NotImplementedError(
35 'Class cannot be instantiated, use get_instance() to get a '
36 'SSHClient instance.')
37
38 @staticmethod
39 def get_instance(hostname, username, port=22, **kwargs):
40 """Return the instance of SSHClient from a pool of active connections,
41 otherwise create a new connection and return."""
42 port = int(port)
43 client = SSHManager.get_client(hostname, username, port)
44 if client:
45 if not client.get_transport().is_active():
46 client.connect(
47 hostname, username=username, port=port, **kwargs)
48 else:
49 client = paramiko.SSHClient()
50 client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
51 client.connect(hostname, username=username, port=port, **kwargs)
52 SSHManager.__connection_pool.append(client)
53 return client
54
55 @staticmethod
56 def sync():
57 """Update the connection pool to only keep alive connections."""
58 pool_copy = SSHManager.__connection_pool.copy()
59 for client in SSHManager.__connection_pool:
60 if not client.get_transport().is_alive():
61 pool_copy.remove(client)
62 SSHManager.__connection_pool = pool_copy
63
64 @staticmethod
65 def get_client(hostname, username, port):
66 """Return the matching client from the pool based on provided
67 constraints."""
68 connections = [
69 client for client in SSHManager.__connection_pool if
70 client.get_transport().getpeername() == (hostname, port) and
71 username == client.get_transport().get_username()
72 ]
73 return connections[0] if connections else None
74
75
76def run_command(command, hostname=None, username=None, port=None):
77 """Run the given command on remote machine over ssh.
78
79 :param command: a string of the command to run.
80 :param hostname: The host to run command on.
81 :param username: Name of the user on the remote host to login to.
82 :param port: SSH port number.
83 :raises ValueError: if command exits with non-zero status.
84 :return: the stdout of the command.
85 """
86 _hostname, _username, _port = get_remote_host_credentials()
87 ssh = SSHManager.get_instance(
88 hostname or _hostname, username or _username, port or _port)
89 _, stdout, stderr = ssh.exec_command(command)
90 if stdout.channel.recv_exit_status() != 0:
91 raise ValueError(stderr.read().decode())
92 return stdout.read().decode()
093
=== added file 'snappy_ecosystem_tests/utils/user.py'
--- snappy_ecosystem_tests/utils/user.py 1970-01-01 00:00:00 +0000
+++ snappy_ecosystem_tests/utils/user.py 2017-02-22 19:08:43 +0000
@@ -0,0 +1,35 @@
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"""Get host user data."""
22
23import os
24
25from snappy_ecosystem_tests.commons.config import USER_CONFIG_STACK
26
27
28def get_remote_host_credentials():
29 """Return credentials for remote machine, to run commands on."""
30 return (USER_CONFIG_STACK.get('user', 'hostname_remote',
31 default=os.environ.get('hostname_remote')),
32 USER_CONFIG_STACK.get('user', 'username_remote',
33 default=os.environ.get('username_remote')),
34 USER_CONFIG_STACK.get('user', 'port_remote',
35 default=os.environ.get('port_remote')))

Subscribers

People subscribed via source and target branches