# Copyright 2015-2016 Yelp Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from mock import ANY from mock import MagicMock from mock import patch from pytest import raises from requests.exceptions import RequestException from requests.exceptions import SSLError from paasta_tools.cli.cli import parse_args from paasta_tools.cli.cmds.push_to_registry import build_command from paasta_tools.cli.cmds.push_to_registry import is_docker_image_already_in_registry from paasta_tools.cli.cmds.push_to_registry import paasta_push_to_registry @patch("paasta_tools.cli.cmds.push_to_registry.build_docker_tag", autospec=True) def test_build_command(mock_build_docker_tag): mock_build_docker_tag.return_value = "my-docker-registry/services-foo:paasta-asdf" expected = "docker push my-docker-registry/services-foo:paasta-asdf" actual = build_command("foo", "bar") assert actual == expected @patch( "paasta_tools.cli.cmds.push_to_registry.is_docker_image_already_in_registry", autospec=True, ) @patch("paasta_tools.cli.cmds.push_to_registry.build_command", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry.validate_service_name", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._run", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log_audit", autospec=True) def test_push_to_registry_run_fail( mock_log_audit, mock_log, mock_run, mock_validate_service_name, mock_build_command, mock_is_docker_image_already_in_registry, ): mock_build_command.return_value = ( "docker push my-docker-registry/services-foo:paasta-asdf" ) mock_is_docker_image_already_in_registry.return_value = False mock_run.return_value = (1, "Bad") args = MagicMock() assert paasta_push_to_registry(args) == 1 assert not mock_log_audit.called @patch( "paasta_tools.cli.cmds.push_to_registry.is_docker_image_already_in_registry", autospec=True, ) @patch("paasta_tools.cli.cmds.push_to_registry.build_command", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry.validate_service_name", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._run", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log_audit", autospec=True) def test_push_to_registry_success( mock_log_audit, mock_log, mock_run, mock_validate_service_name, mock_build_command, mock_is_docker_image_already_in_registry, ): args, _ = parse_args(["push-to-registry", "-s", "foo", "-c", "abcd" * 10]) mock_build_command.return_value = ( "docker push my-docker-registry/services-foo:paasta-asdf" ) mock_run.return_value = (0, "Success") mock_is_docker_image_already_in_registry.return_value = False assert paasta_push_to_registry(args) == 0 assert mock_build_command.called assert mock_run.called mock_log_audit.assert_called_once_with( action="push-to-registry", action_details={"commit": "abcd" * 10}, service="foo" ) @patch( "paasta_tools.cli.cmds.push_to_registry.is_docker_image_already_in_registry", autospec=True, ) @patch("paasta_tools.cli.cmds.push_to_registry.build_command", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry.validate_service_name", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._run", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log_audit", autospec=True) def test_push_to_registry_force( mock_log_audit, mock_log, mock_run, mock_validate_service_name, mock_build_command, mock_is_docker_image_already_in_registry, ): args, _ = parse_args( ["push-to-registry", "-s", "foo", "-c", "abcd" * 10, "--force"] ) mock_build_command.return_value = ( "docker push fake_registry/services-foo:paasta-abcd" ) mock_run.return_value = (0, "Success") assert paasta_push_to_registry(args) == 0 assert not mock_is_docker_image_already_in_registry.called mock_run.assert_called_once_with( "docker push fake_registry/services-foo:" "paasta-abcd", component="build", log=True, loglevel="debug", service="foo", timeout=3600, ) mock_log_audit.assert_called_once_with( action="push-to-registry", action_details={"commit": "abcd" * 10}, service="foo" ) @patch( "paasta_tools.cli.cmds.push_to_registry.is_docker_image_already_in_registry", autospec=True, ) @patch("paasta_tools.cli.cmds.push_to_registry.build_command", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry.validate_service_name", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._run", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log_audit", autospec=True) def test_push_to_registry_does_not_override_existing_image( mock_log_audit, mock_log, mock_run, mock_validate_service_name, mock_build_command, mock_is_docker_image_already_in_registry, ): args, _ = parse_args(["push-to-registry", "-s", "foo", "-c", "abcd" * 10]) mock_run.return_value = (0, "Success") mock_is_docker_image_already_in_registry.return_value = True assert paasta_push_to_registry(args) == 0 assert not mock_build_command.called assert not mock_run.called assert not mock_log_audit.called @patch("paasta_tools.utils.load_system_paasta_config", autospec=True) @patch( "paasta_tools.cli.cmds.push_to_registry.is_docker_image_already_in_registry", autospec=True, ) @patch("paasta_tools.cli.cmds.push_to_registry.build_command", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry.validate_service_name", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._run", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log_audit", autospec=True) def test_push_to_registry_does_not_override_when_cant_check_status( mock_log_audit, mock_log, mock_run, mock_validate_service_name, mock_build_command, mock_is_docker_image_already_in_registry, mock_load_system_paasta_config, ): args, _ = parse_args(["push-to-registry", "-s", "foo", "-c", "abcd" * 10]) mock_run.return_value = (0, "Success") mock_is_docker_image_already_in_registry.side_effect = RequestException() assert paasta_push_to_registry(args) == 1 assert not mock_build_command.called assert not mock_run.called assert not mock_log_audit.called @patch( "paasta_tools.cli.cmds.push_to_registry.is_docker_image_already_in_registry", autospec=True, ) @patch("paasta_tools.cli.cmds.push_to_registry.validate_service_name", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._run", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry._log_audit", autospec=True) @patch("paasta_tools.cli.cmds.push_to_registry.build_command", autospec=True) def test_push_to_registry_works_when_service_name_starts_with_services_dash( mock_build_command, mock_log_audit, mock_log, mock_run, mock_validate_service_name, mock_is_docker_image_already_in_registry, ): args, _ = parse_args(["push-to-registry", "-s", "foo", "-c", "abcd" * 10]) mock_run.return_value = (0, "Success") mock_is_docker_image_already_in_registry.return_value = False assert paasta_push_to_registry(args) == 0 mock_build_command.assert_called_once_with("foo", "abcd" * 10) mock_log_audit.assert_called_once_with( action="push-to-registry", action_details={"commit": "abcd" * 10}, service="foo" ) @patch( "paasta_tools.cli.cmds.push_to_registry.get_service_docker_registry", autospec=True ) @patch("paasta_tools.cli.cmds.push_to_registry.requests.Session.head", autospec=True) @patch( "paasta_tools.cli.cmds.push_to_registry.read_docker_registry_creds", autospec=True ) def test_is_docker_image_already_in_registry_success( mock_read_docker_registry_creds, mock_request_head, mock_get_service_docker_registry ): mock_read_docker_registry_creds.return_value = (None, None) mock_get_service_docker_registry.return_value = "registry" mock_request_head.return_value = MagicMock(status_code=200) assert is_docker_image_already_in_registry( "fake_service", "fake_soa_dir", "fake_sha" ) mock_request_head.assert_called_with( ANY, "https://registry/v2/services-fake_service/manifests/paasta-fake_sha", timeout=30, ) @patch( "paasta_tools.cli.cmds.push_to_registry.get_service_docker_registry", autospec=True ) @patch("paasta_tools.cli.cmds.push_to_registry.requests.Session.head", autospec=True) @patch( "paasta_tools.cli.cmds.push_to_registry.read_docker_registry_creds", autospec=True ) def test_is_docker_image_already_in_registry_success_with_registry_credentials( mock_read_docker_registry_creds, mock_request_head, mock_get_service_docker_registry ): auth = ("username", "password") mock_read_docker_registry_creds.return_value = auth mock_get_service_docker_registry.return_value = "registry" mock_request_head.return_value = MagicMock(status_code=200) assert is_docker_image_already_in_registry( "fake_service", "fake_soa_dir", "fake_sha" ) mock_request_head.assert_called_with( ANY, "https://registry/v2/services-fake_service/manifests/paasta-fake_sha", auth=auth, timeout=30, ) @patch( "paasta_tools.cli.cmds.push_to_registry.get_service_docker_registry", autospec=True ) @patch("paasta_tools.cli.cmds.push_to_registry.requests.Session.head", autospec=True) @patch( "paasta_tools.cli.cmds.push_to_registry.read_docker_registry_creds", autospec=True ) def test_is_docker_image_already_in_registry_404_no_such_service_yet( mock_read_docker_registry_creds, mock_request_head, mock_get_service_docker_registry ): mock_read_docker_registry_creds.return_value = (None, None) mock_get_service_docker_registry.return_value = "registry" mock_request_head.return_value = MagicMock( status_code=404 ) # No Such Repository Error assert not is_docker_image_already_in_registry( "fake_service", "fake_soa_dir", "fake_sha" ) mock_request_head.assert_called_with( ANY, "https://registry/v2/services-fake_service/manifests/paasta-fake_sha", timeout=30, ) @patch( "paasta_tools.cli.cmds.push_to_registry.get_service_docker_registry", autospec=True ) @patch("paasta_tools.cli.cmds.push_to_registry.requests.Session.head", autospec=True) @patch( "paasta_tools.cli.cmds.push_to_registry.read_docker_registry_creds", autospec=True ) def test_is_docker_image_already_when_image_does_not_exist( mock_read_docker_registry_creds, mock_request_head, mock_get_service_docker_registry ): mock_read_docker_registry_creds.return_value = (None, None) mock_get_service_docker_registry.return_value = "registry" mock_request_head.return_value = MagicMock(status_code=404) assert not is_docker_image_already_in_registry( "fake_service", "fake_soa_dir", "fake_sha" ) mock_request_head.assert_called_with( ANY, "https://registry/v2/services-fake_service/manifests/paasta-fake_sha", timeout=30, ) @patch( "paasta_tools.cli.cmds.push_to_registry.get_service_docker_registry", autospec=True ) @patch("paasta_tools.cli.cmds.push_to_registry.requests.Session.head", autospec=True) @patch( "paasta_tools.cli.cmds.push_to_registry.read_docker_registry_creds", autospec=True ) def test_is_docker_image_already_in_registry_401_unauthorized( mock_read_docker_registry_creds, mock_request_head, mock_get_service_docker_registry ): mock_read_docker_registry_creds.return_value = (None, None) mock_request_head.side_effect = RequestException() with raises(RequestException): is_docker_image_already_in_registry("fake_service", "fake_soa_dir", "fake_sha") @patch( "paasta_tools.cli.cmds.push_to_registry.get_service_docker_registry", autospec=True ) @patch("paasta_tools.cli.cmds.push_to_registry.requests.Session.head", autospec=True) @patch( "paasta_tools.cli.cmds.push_to_registry.read_docker_registry_creds", autospec=True ) def test_is_docker_image_already_in_registry_http_when_image_does_not_exist( mock_read_docker_registry_creds, mock_request_head, mock_get_service_docker_registry ): def mock_head(session, url, timeout): if url.startswith("https"): raise SSLError("Uh oh") return MagicMock(status_code=404) mock_get_service_docker_registry.return_value = "registry" mock_request_head.side_effect = mock_head mock_read_docker_registry_creds.return_value = (None, None) assert not is_docker_image_already_in_registry( "fake_service", "fake_soa_dir", "fake_sha" ) mock_request_head.assert_called_with( ANY, "http://registry/v2/services-fake_service/manifests/paasta-fake_sha", timeout=30, )