diff -Nru landscape-client-14.12/debian/changelog landscape-client-14.12/debian/changelog --- landscape-client-14.12/debian/changelog 2017-08-08 12:18:06.000000000 +0000 +++ landscape-client-14.12/debian/changelog 2017-09-13 20:46:09.000000000 +0000 @@ -1,3 +1,9 @@ +landscape-client (14.12-0ubuntu7.14.04) trusty; urgency=medium + + * Add proxy handling to package reporter. (LP: #1531150) + + -- Simon Poirier Wed, 13 Sep 2017 20:21:12 +0000 + landscape-client (14.12-0ubuntu6.14.04) trusty; urgency=medium * Minor updates (LP: #1636477): diff -Nru landscape-client-14.12/debian/patches/package-reporter-proxy-1531150.diff landscape-client-14.12/debian/patches/package-reporter-proxy-1531150.diff --- landscape-client-14.12/debian/patches/package-reporter-proxy-1531150.diff 1970-01-01 00:00:00.000000000 +0000 +++ landscape-client-14.12/debian/patches/package-reporter-proxy-1531150.diff 2017-09-13 20:53:12.000000000 +0000 @@ -0,0 +1,274 @@ +Index: landscape-client-14.12/apt-update/apt-update.c +=================================================================== +--- landscape-client-14.12.orig/apt-update/apt-update.c 2017-09-13 20:53:07.486574090 +0000 ++++ landscape-client-14.12/apt-update/apt-update.c 2017-09-13 20:53:07.482574087 +0000 +@@ -19,7 +19,7 @@ + int main(int argc, char *argv[], char *envp[]) + { + char *apt_argv[] = {"/usr/bin/apt-get", "-q", "update", NULL}; +- char *apt_envp[] = {"PATH=/bin:/usr/bin", NULL, NULL}; ++ char *apt_envp[] = {"PATH=/bin:/usr/bin", NULL, NULL, NULL, NULL}; + + // Set the HOME environment variable + struct passwd *pwd = getpwuid(geteuid()); +@@ -33,6 +33,24 @@ + exit(1); + } + ++ // Pass proxy environment variables ++ int proxy_arg = 2; ++ char *http_proxy = getenv("http_proxy"); ++ if (http_proxy) { ++ if (asprintf(&apt_envp[proxy_arg], "http_proxy=%s", http_proxy) == -1) { ++ perror("error: Unable to set http_proxy environment variable"); ++ exit(1); ++ } ++ proxy_arg++; ++ } ++ char *https_proxy = getenv("https_proxy"); ++ if (https_proxy) { ++ if (asprintf(&apt_envp[proxy_arg], "https_proxy=%s", https_proxy) == -1) { ++ perror("error: Unable to set https_proxy environment variable"); ++ exit(1); ++ } ++ } ++ + // Drop any supplementary group + if (setgroups(0, NULL) == -1) { + perror("error: Unable to set supplementary groups IDs"); +Index: landscape-client-14.12/landscape/lib/fetch.py +=================================================================== +--- landscape-client-14.12.orig/landscape/lib/fetch.py 2017-09-13 20:53:07.486574090 +0000 ++++ landscape-client-14.12/landscape/lib/fetch.py 2017-09-13 20:53:07.482574087 +0000 +@@ -45,7 +45,7 @@ + + def fetch(url, post=False, data="", headers={}, cainfo=None, curl=None, + connect_timeout=30, total_timeout=600, insecure=False, follow=True, +- user_agent=None): ++ user_agent=None, proxy=None): + """Retrieve a URL and return the content. + + @param url: The url to be fetched. +@@ -61,6 +61,7 @@ + during autodiscovery) + @param follow: If True, follow HTTP redirects (default True). + @param user_agent: The user-agent to set in the request. ++ @param proxy: The proxy url to use for the request. + """ + import pycurl + output = StringIO(data) +@@ -94,6 +95,9 @@ + if user_agent is not None: + curl.setopt(pycurl.USERAGENT, user_agent) + ++ if proxy is not None: ++ curl.setopt(pycurl.PROXY, proxy) ++ + curl.setopt(pycurl.MAXREDIRS, 5) + curl.setopt(pycurl.CONNECTTIMEOUT, connect_timeout) + curl.setopt(pycurl.LOW_SPEED_LIMIT, 1) +Index: landscape-client-14.12/landscape/lib/tests/test_fetch.py +=================================================================== +--- landscape-client-14.12.orig/landscape/lib/tests/test_fetch.py 2017-09-13 20:53:07.486574090 +0000 ++++ landscape-client-14.12/landscape/lib/tests/test_fetch.py 2017-09-13 20:53:07.482574087 +0000 +@@ -279,6 +279,14 @@ + self.assertEqual(result, "result") + self.assertEqual("user-agent", curl.options[pycurl.USERAGENT]) + ++ def test_pycurl_proxy(self): ++ """If provided, the proxy is set in the request.""" ++ curl = CurlStub("result") ++ proxy = "http://my.little.proxy" ++ result = fetch("http://example.com", curl=curl, proxy=proxy) ++ self.assertEqual("result", result) ++ self.assertEqual(proxy, curl.options[pycurl.PROXY]) ++ + def test_create_curl(self): + curls = [] + +Index: landscape-client-14.12/landscape/package/reporter.py +=================================================================== +--- landscape-client-14.12.orig/landscape/package/reporter.py 2017-09-13 20:53:07.486574090 +0000 ++++ landscape-client-14.12/landscape/package/reporter.py 2017-09-13 20:53:07.482574087 +0000 +@@ -38,6 +38,10 @@ + parser.add_option("--force-apt-update", default=False, + action="store_true", + help="Force running apt-update.") ++ parser.add_option("--http-proxy", metavar="URL", ++ help="The URL of the HTTP proxy, if one is needed.") ++ parser.add_option("--https-proxy", metavar="URL", ++ help="The URL of the HTTPS proxy, if one is needed.") + return parser + + +@@ -133,8 +137,14 @@ + logging.warning("Couldn't download hash=>id database: %s" % + str(exception)) + ++ if url.startswith("https"): ++ proxy = self._config.get("https_proxy") ++ else: ++ proxy = self._config.get("http_proxy") ++ + result = fetch_async(url, +- cainfo=self._config.get("ssl_public_key")) ++ cainfo=self._config.get("ssl_public_key"), ++ proxy=proxy) + result.addCallback(fetch_ok) + result.addErrback(fetch_error) + +@@ -262,7 +272,12 @@ + Run apt-update using the passed in deferred, which allows for callers + to inspect the result code. + """ +- result = spawn_process(self.apt_update_filename) ++ env = {} ++ if self._config.http_proxy: ++ env["http_proxy"] = self._config.http_proxy ++ if self._config.https_proxy: ++ env["https_proxy"] = self._config.https_proxy ++ result = spawn_process(self.apt_update_filename, env=env) + + def callback((out, err, code), deferred): + return deferred.callback((out, err, code)) +Index: landscape-client-14.12/landscape/package/tests/test_reporter.py +=================================================================== +--- landscape-client-14.12.orig/landscape/package/tests/test_reporter.py 2017-09-13 20:53:07.486574090 +0000 ++++ landscape-client-14.12/landscape/package/tests/test_reporter.py 2017-09-13 20:53:07.482574087 +0000 +@@ -3,11 +3,11 @@ + import time + import apt_pkg + import shutil ++import mock + + from twisted.internet.defer import Deferred, succeed, inlineCallbacks + from twisted.internet import reactor + +- + from landscape.lib.fs import create_file, touch_file + from landscape.lib.fetch import fetch_async, FetchError + from landscape.lib.lsb_release import parse_lsb_release, LSB_RELEASE_FILENAME +@@ -286,7 +286,7 @@ + hash_id_db_url = self.config.package_hash_id_url + "uuid_codename_arch" + fetch_async_mock = self.mocker.replace("landscape.lib." + "fetch.fetch_async") +- fetch_async_mock(hash_id_db_url, cainfo=None) ++ fetch_async_mock(hash_id_db_url, cainfo=None, patch=None) + fetch_async_result = Deferred() + fetch_async_result.callback("hash-ids") + self.mocker.result(fetch_async_result) +@@ -311,6 +311,33 @@ + + return result + ++ @mock.patch("landscape.package.reporter.fetch_async", ++ return_value=succeed("hash-ids")) ++ @mock.patch("logging.info", return_value=None) ++ def test_fetch_hash_id_db_with_proxy(self, logging_mock, mock_fetch_async): ++ """fetching hash-id-db uses proxy settings""" ++ # Assume package_hash_id_url is set ++ self.config.data_path = self.makeDir() ++ self.config.package_hash_id_url = "https://fake.url/path/" ++ os.makedirs(os.path.join(self.config.data_path, "package", "hash-id")) ++ ++ # Fake uuid, codename and arch ++ message_store = self.broker_service.message_store ++ message_store.set_server_uuid("uuid") ++ self.reporter.lsb_release_filename = self.makeFile(SAMPLE_LSB_RELEASE) ++ self.facade.set_arch("arch") ++ ++ # Let's say fetch_async is successful ++ hash_id_db_url = self.config.package_hash_id_url + "uuid_codename_arch" ++ ++ # set proxy settings ++ self.config.https_proxy = "http://helloproxy:8000" ++ ++ result = self.reporter.fetch_hash_id_db() ++ mock_fetch_async.assert_called_once_with( ++ hash_id_db_url, cainfo=None, proxy="http://helloproxy:8000") ++ return result ++ + def test_fetch_hash_id_db_does_not_download_twice(self): + + # Let's say that the hash=>id database is already there +@@ -330,7 +357,7 @@ + # Intercept any call to fetch_async + fetch_async_mock = self.mocker.replace("landscape.lib." + "fetch.fetch_async") +- fetch_async_mock(ANY) ++ fetch_async_mock(ANY, proxy=None) + + # Go! + self.mocker.replay() +@@ -430,7 +457,7 @@ + "uuid_codename_arch" + fetch_async_mock = self.mocker.replace("landscape.lib." + "fetch.fetch_async") +- fetch_async_mock(hash_id_db_url, cainfo=None) ++ fetch_async_mock(hash_id_db_url, cainfo=None, proxy=None) + fetch_async_result = Deferred() + fetch_async_result.callback("hash-ids") + self.mocker.result(fetch_async_result) +@@ -462,7 +489,7 @@ + hash_id_db_url = self.config.package_hash_id_url + "uuid_codename_arch" + fetch_async_mock = self.mocker.replace("landscape.lib." + "fetch.fetch_async") +- fetch_async_mock(hash_id_db_url, cainfo=None) ++ fetch_async_mock(hash_id_db_url, cainfo=None, proxy=None) + fetch_async_result = Deferred() + fetch_async_result.errback(FetchError("fetch error")) + self.mocker.result(fetch_async_result) +@@ -538,7 +565,7 @@ + "uuid_codename_arch" + fetch_async_mock = self.mocker.replace("landscape.lib." + "fetch.fetch_async") +- fetch_async_mock(hash_id_db_url, cainfo=self.config.ssl_public_key) ++ fetch_async_mock(hash_id_db_url, cainfo=self.config.ssl_public_key, proxy=None) + fetch_async_result = Deferred() + fetch_async_result.callback("hash-ids") + self.mocker.result(fetch_async_result) +@@ -1621,6 +1648,44 @@ + reactor.callWhenRunning(do_test) + return deferred + ++ @mock.patch("landscape.package.reporter.spawn_process", ++ return_value=succeed(("", "", 0))) ++ def test_run_apt_update_honors_http_proxy(self, mock_spawn_process): ++ """ ++ The PackageReporter.run_apt_update method honors the http_proxy ++ config when calling the apt-update wrapper. ++ """ ++ self.config.http_proxy = "http://proxy_server:8080" ++ self.reporter.sources_list_filename = "/I/Dont/Exist" ++ ++ update_result = self.reporter.run_apt_update() ++ # run_apt_update uses reactor.call_later so advance a bit ++ self.reactor.advance(0) ++ self.successResultOf(update_result) ++ ++ mock_spawn_process.assert_called_once_with( ++ self.reporter.apt_update_filename, ++ env={"http_proxy": "http://proxy_server:8080"}) ++ ++ @mock.patch("landscape.package.reporter.spawn_process", ++ return_value=succeed(("", "", 0))) ++ def test_run_apt_update_honors_https_proxy(self, mock_spawn_process): ++ """ ++ The PackageReporter.run_apt_update method honors the https_proxy ++ config when calling the apt-update wrapper. ++ """ ++ self.config.https_proxy = "http://proxy_server:8443" ++ self.reporter.sources_list_filename = "/I/Dont/Exist" ++ ++ update_result = self.reporter.run_apt_update() ++ # run_apt_update uses reactor.call_later, so advance a bit ++ self.reactor.advance(0) ++ self.successResultOf(update_result) ++ ++ mock_spawn_process.assert_called_once_with( ++ self.reporter.apt_update_filename, ++ env={"https_proxy": "http://proxy_server:8443"}) ++ + def test_run_apt_update_error_on_cache_file(self): + """ + L{PackageReporter.run_apt_update} succeeds if the command fails because diff -Nru landscape-client-14.12/debian/patches/series landscape-client-14.12/debian/patches/series --- landscape-client-14.12/debian/patches/series 2017-08-08 12:18:06.000000000 +0000 +++ landscape-client-14.12/debian/patches/series 2017-09-13 20:52:53.000000000 +0000 @@ -10,3 +10,4 @@ bug-1532887-revno-825.diff bug-1508110-revno-826.diff bug-1508110-revno-829.diff +package-reporter-proxy-1531150.diff