def test_search_distributor_with_relative_url():
    controller = FakeController()

    dist1 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo1",
        relative_url="relative/path",
    )
    dist2 = Distributor(
        id="cdn_distributor",
        type_id="rpm_rsync_distributor",
        repo_id="repo1",
        relative_url="relative/path",
    )
    repo1 = Repository(id="repo1", distributors=(dist1, dist2))

    dist3 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo2",
        relative_url="another/path",
    )

    repo2 = Repository(id="repo2", distributors=(dist3, ))

    controller.insert_repository(repo1)
    controller.insert_repository(repo2)

    client = controller.client
    crit = Criteria.with_field("relative_url", Matcher.regex("relative/path"))

    found = client.search_distributor(crit).result().data

    assert sorted(found) == [dist2, dist1]
Esempio n. 2
0
def test_publish_absent_raises():
    """repo.publish() of a nonexistent repo raises."""
    controller = FakeController()

    controller.insert_repository(
        YumRepository(
            id="repo1",
            distributors=[
                Distributor(id="yum_distributor", type_id="yum_distributor"),
                Distributor(id="cdn_distributor",
                            type_id="rpm_rsync_distributor"),
            ],
        ))

    client = controller.client
    repo_copy1 = client.get_repository("repo1")
    repo_copy2 = client.get_repository("repo1")

    # If I delete the repo through one handle...
    assert repo_copy1.delete().result()

    # ...then publish through the other handle becomes impossible
    exception = repo_copy2.publish().exception()
    assert isinstance(exception, PulpException)
    assert "repo1 not found" in str(exception)
def test_search_mapped_field_less_than():
    controller = FakeController()

    dist1 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo1",
        last_publish=datetime.datetime(2019, 8, 23, 2, 5, 0, tzinfo=None),
    )
    dist2 = Distributor(
        id="cdn_distributor",
        type_id="rpm_rsync_distributor",
        repo_id="repo1",
        last_publish=datetime.datetime(2019, 8, 27, 2, 5, 0, tzinfo=None),
    )
    repo1 = Repository(id="repo1", distributors=(dist1, dist2))

    controller.insert_repository(repo1)

    client = controller.client
    crit = Criteria.with_field(
        "last_publish",
        Matcher.less_than(datetime.datetime(2019, 8, 24, 0, 0, 0)))
    found = client.search_distributor(crit).result().data

    assert found == [dist1]
Esempio n. 4
0
def test_publish_retries(fast_poller, requests_mocker, client, caplog):
    """publish retries distributors as they fail"""
    caplog.set_level(logging.WARNING)

    repo = YumRepository(
        id="some-repo",
        distributors=(
            Distributor(id="yum_distributor", type_id="yum_distributor"),
            Distributor(id="cdn_distributor", type_id="cdn_distributor"),
        ),
    )
    repo.__dict__["_client"] = client

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        [
            {"json": {"spawned_tasks": [{"task_id": "task1"}]}},
            {"json": {"spawned_tasks": [{"task_id": "task2"}]}},
            {"json": {"spawned_tasks": [{"task_id": "task3"}]}},
        ],
    )

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/tasks/search/",
        [
            {"json": [{"task_id": "task1", "state": "finished"}]},
            {"json": [{"task_id": "task2", "state": "error"}]},
            {"json": [{"task_id": "task3", "state": "finished"}]},
        ],
    )

    publish_f = repo.publish()

    # It should succeed
    tasks = publish_f.result()

    # It should return only the *successful* tasks
    assert sorted([t.id for t in tasks]) == ["task1", "task3"]

    # Pick out the HTTP requests triggering distributors
    publish_reqs = [
        req
        for req in requests_mocker.request_history
        if req.url
        == "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/"
    ]
    publish_distributors = [req.json()["id"] for req in publish_reqs]

    # It should have triggered cdn_distributor twice, since the first attempt failed
    assert publish_distributors == [
        "yum_distributor",
        "cdn_distributor",
        "cdn_distributor",
    ]

    # The retry should have been logged
    messages = caplog.messages
    assert (
        messages[-1].splitlines()[0] == "Retrying due to error: Task task2 failed [1/6]"
    )
Esempio n. 5
0
def test_can_publish():
    """repo.publish() succeeds with fake client and populates publish_history."""
    controller = FakeController()

    controller.insert_repository(
        YumRepository(
            id="repo1",
            distributors=[
                Distributor(id="yum_distributor", type_id="yum_distributor"),
                Distributor(id="cdn_distributor",
                            type_id="rpm_rsync_distributor"),
            ],
        ))
    controller.insert_repository(YumRepository(id="repo2"))

    client = controller.client
    repo1 = client.get_repository("repo1")

    # Call to publish should succeed
    publish_f = repo1.publish()

    # The future should resolve successfully
    tasks = publish_f.result()

    # It should have returned at least one successful task.
    assert tasks
    for task in tasks:
        assert task.succeeded

    # The change should be reflected in the controller's publish history
    history = controller.publish_history

    assert len(history) == 1
    assert history[0].repository.id == "repo1"
    assert history[0].tasks == tasks
Esempio n. 6
0
def _add_repo(controller):
    # test repos added to the controller
    dt1 = datetime(2019, 9, 10, 0, 0, 0)
    r1_d1 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo1",
        last_publish=dt1,
        relative_url="content/unit/1/client",
    )
    r1_d2 = Distributor(
        id="cdn_distributor",
        type_id="rpm_rsync_distributor",
        repo_id="repo1",
        last_publish=dt1,
        relative_url="content/unit/1/client",
    )
    repo1 = Repository(
        id="repo1",
        eng_product_id=101,
        distributors=[r1_d1, r1_d2],
        relative_url="content/unit/1/client",
        mutable_urls=["mutable1", "mutable2"],
    )

    dt2 = datetime(2019, 9, 12, 0, 0, 0)
    d2 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo2",
        last_publish=dt2,
        relative_url="content/unit/2/client",
    )
    repo2 = Repository(
        id="repo2",
        eng_product_id=102,
        distributors=[d2],
        relative_url="content/unit/2/client",
    )

    dt3 = datetime(2019, 9, 7, 0, 0, 0)
    d3 = Distributor(
        id="cdn_distributor",
        type_id="rpm_rsync_distributor",
        repo_id="repo3",
        last_publish=dt3,
        relative_url="content/unit/3/client",
    )
    repo3 = Repository(
        id="repo3",
        eng_product_id=103,
        distributors=[d3],
        relative_url="content/unit/3/client",
    )

    controller.insert_repository(repo1)
    controller.insert_repository(repo2)
    controller.insert_repository(repo3)
def test_publish_cancel(fast_poller, requests_mocker, client, caplog):
    """Cancelling a publish future will cancel running Pulp task(s)."""

    repo = YumRepository(
        id="some-repo",
        distributors=(
            Distributor(id="yum_distributor", type_id="yum_distributor"),
            Distributor(id="cdn_distributor", type_id="cdn_distributor"),
        ),
    )
    repo.__dict__["_client"] = client

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        [{
            "json": {
                "spawned_tasks": [{
                    "task_id": "task1"
                }]
            }
        }],
    )

    task_search_url = "https://pulp.example.com/pulp/api/v2/tasks/search/"
    requests_mocker.post(task_search_url, [{
        "json": [{
            "task_id": "task1",
            "state": "running"
        }]
    }])

    requests_mocker.delete("https://pulp.example.com/pulp/api/v2/tasks/task1/")

    # Start the publish
    publish_f = repo.publish()

    # Wait until we're sure poll thread has seen this task
    for _ in range(0, 1000):
        if (requests_mocker.last_request
                and requests_mocker.last_request.url == task_search_url):
            break
        time.sleep(0.001)
    assert requests_mocker.last_request.url == task_search_url

    # We should be able to cancel it
    assert publish_f.cancel()

    # It should have cancelled the underlying Pulp task
    task_req = [
        r for r in requests_mocker.request_history
        if r.url == "https://pulp.example.com/pulp/api/v2/tasks/task1/"
    ]
    assert len(task_req) == 1
    assert task_req[0].method == "DELETE"
Esempio n. 8
0
def test_publish_with_options(requests_mocker, client):
    """publish passes expected config into distributors based on publish options"""
    repo = YumRepository(
        id="some-repo",
        distributors=(
            Distributor(id="yum_distributor", type_id="yum_distributor"),
            Distributor(id="cdn_distributor", type_id="rpm_rsync_distributor"),
        ),
    )
    repo.__dict__["_client"] = client

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        [
            {"json": {"spawned_tasks": [{"task_id": "task1"}]}},
            {"json": {"spawned_tasks": [{"task_id": "task2"}]}},
        ],
    )

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/tasks/search/",
        [
            {"json": [{"task_id": "task1", "state": "finished"}]},
            {"json": [{"task_id": "task2", "state": "finished"}]},
        ],
    )

    options = PublishOptions(
        clean=True, force=True, origin_only=True, rsync_extra_args=["-a"]
    )

    # It should have succeeded, with the tasks as retrieved from Pulp
    assert sorted(repo.publish(options)) == [
        Task(id="task1", succeeded=True, completed=True),
        Task(id="task2", succeeded=True, completed=True),
    ]

    req = requests_mocker.request_history

    # The yum_distributor request should have set force_full, but not
    # delete since it's not recognized by that distributor
    assert req[0].json()["override_config"] == {"force_full": True}

    # The cdn_distributor request should have set force_full, delete
    # and content_units_only
    assert req[2].json()["override_config"] == {
        "force_full": True,
        "delete": True,
        "content_units_only": True,
        "rsync_extra_args": ["-a"],
    }
Esempio n. 9
0
def test_publish_order(requests_mocker, client):
    """publish runs docker/rsync distributors in correct order"""
    repo = ContainerImageRepository(
        id="some-repo",
        distributors=(
            Distributor(
                id="docker_web_distributor_name_cli", type_id="docker_distributor_web"
            ),
            Distributor(id="cdn_distributor", type_id="docker_rsync_distributor"),
            Distributor(
                id="cdn_distributor_unprotected", type_id="docker_rsync_distributor"
            ),
        ),
    )
    repo.__dict__["_client"] = client

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        [
            {"json": {"spawned_tasks": [{"task_id": "task1"}]}},
            {"json": {"spawned_tasks": [{"task_id": "task2"}]}},
            {"json": {"spawned_tasks": [{"task_id": "task3"}]}},
        ],
    )

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/tasks/search/",
        [
            {"json": [{"task_id": "task1", "state": "finished"}]},
            {"json": [{"task_id": "task2", "state": "finished"}]},
            {"json": [{"task_id": "task3", "state": "finished"}]},
        ],
    )

    # It should have succeeded, with the tasks as retrieved from Pulp
    assert sorted(repo.publish().result()) == [
        Task(id="task1", succeeded=True, completed=True),
        Task(id="task2", succeeded=True, completed=True),
        Task(id="task3", succeeded=True, completed=True),
    ]

    req = requests_mocker.request_history
    ids = [r.json()["id"] for r in req if r.url.endswith("/publish/")]

    # It should have triggered these distributors in this order
    assert ids == [
        "cdn_distributor",
        "cdn_distributor_unprotected",
        "docker_web_distributor_name_cli",
    ]
def test_delete_missing_repo_fails():
    """dist.delete() of distributor with absent repo fails."""
    controller = FakeController()

    controller.insert_repository(
        Repository(
            id="repo",
            distributors=[
                Distributor(id="somedist", type_id="sometype", repo_id="repo")
            ],
        ))

    client = controller.client

    # Get two handles to the repo, to set up the situation that
    # the distributor is not detached despite repo deletion
    repo1 = client.get_repository("repo")
    repo2 = client.get_repository("repo")
    dist = repo2.distributors[0]

    # We can delete the repo
    assert repo1.delete().result()

    # The distributor (obtained via repo2) is not detached, but nevertheless
    # deletion should fail as repo no longer exists
    assert "Repository id=repo not found" in str(dist.delete().exception())
def test_publish_fail(fast_poller, requests_mocker, client):
    """publish raises TaskFailedException if publish task fails"""
    repo = YumRepository(
        id="some-repo",
        distributors=(Distributor(id="yum_distributor",
                                  type_id="yum_distributor"), ),
    )
    repo.__dict__["_client"] = client

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        json={"spawned_tasks": [{
            "task_id": "task1"
        }]},
    )

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/tasks/search/",
        json=[{
            "task_id": "task1",
            "state": "error"
        }],
    )

    publish_f = repo.publish()

    # It should raise this exception
    with pytest.raises(TaskFailedException) as error:
        publish_f.result()

    # The exception should have a reference to the task which failed
    assert error.value.task.id == "task1"
    assert "Task task1 failed" in str(error.value)
Esempio n. 12
0
def test_maintenance_on_with_regex(command_tester):
    """Test set maintenance by using regex"""
    repo1 = Repository(id="repo1")

    dist1 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        relative_url="rhel/7",
        repo_id="repo2",
    )

    repo2 = Repository(id="repo2", distributors=(dist1, ))

    with get_task_instance(True, repo1, repo2) as task_instance:
        command_tester.test(
            task_instance.main,
            [
                "test-maintenance-on",
                "--pulp-url",
                "http://some.url",
                "--repo-url-regex",
                "rhel",
            ],
        )

    assert_expected_report(["repo2"], task_instance.pulp_client)
Esempio n. 13
0
def get_task_instance(on, *repos):

    iso_distributor = Distributor(
        id="iso_distributor",
        type_id="iso_distributor",
        relative_url="root",
        repo_id="redhat-maintenance",
    )
    maint_repo = FileRepository(id="redhat-maintenance",
                                distributors=[iso_distributor])

    if on:
        task_instance = FakeSetMaintenanceOn()
        task_instance.pulp_client_controller.insert_repository(maint_repo)
    else:
        task_instance = FakeSetMaintenanceOff()
        task_instance.pulp_client_controller.insert_repository(maint_repo)
        # if unset maintenance mode, we need to pre-set maintenance first
        report = task_instance.pulp_client.get_maintenance_report().result()
        report = report.add([repo.id for repo in repos])
        task_instance.pulp_client.set_maintenance(report)

    for repo in list(repos):
        task_instance.pulp_client_controller.insert_repository(repo)

    return task_instance
def test_distributors_created():
    """from_data sets distributors attribute appropriately"""
    repo = Repository.from_data(
        {
            "id": "some-repo",
            "distributors": [
                {"id": "dist1", "distributor_type_id": "type1"},
                {"id": "dist2", "distributor_type_id": "type1"},
            ],
        }
    )

    assert repo.distributors == (
        Distributor(id="dist1", type_id="type1"),
        Distributor(id="dist2", type_id="type1"),
    )
Esempio n. 15
0
def test_publish_out_repos(mock_ubipop_runner):
    dt = datetime(2019, 9, 12, 0, 0, 0)

    d1 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo",
        last_publish=dt,
        relative_url="content/unit/2/client",
    )
    repo = YumRepository(
        id="repo",
        eng_product_id=102,
        distributors=[d1],
        relative_url="content/unit/2/client",
    )
    fake_pulp = FakeController()
    repo.__dict__["_client"] = fake_pulp.client

    fake_pulp.insert_repository(repo)
    # Setup output repos, leave only binary repo as the actual one
    mock_ubipop_runner.repos.out_repos = RepoSet(
        f_proxy(f_return(repo)), f_proxy(f_return()), f_proxy(f_return())
    )

    fts = mock_ubipop_runner._publish_out_repos()

    # we should publish only one repository with one distributor
    assert len(fts) == 1
    assert [hist.repository.id for hist in fake_pulp.publish_history] == ["repo"]
def test_delete_missing_distributor_succeeds():
    """dist.delete() of absent distributor with fake client succeeds.

    Deleting a distributor succeeds with the fake client since it also succeeds
    with the real client.
    """
    controller = FakeController()

    controller.insert_repository(
        Repository(
            id="repo",
            distributors=[
                Distributor(id="somedist", type_id="sometype", repo_id="repo")
            ],
        ))

    client = controller.client

    # Get two handles to the repos/distributors so we can delete via one handle
    # and try to delete again via the other
    repo_copy1 = client.get_repository("repo")
    repo_copy2 = client.get_repository("repo")

    dist_copy1 = repo_copy1.distributors[0]
    dist_copy2 = repo_copy2.distributors[0]

    # First delete succeeds, with some tasks
    assert dist_copy1.delete().result()

    # Second delete also succeeds, but there are no tasks since distributor
    # already doesn't exist
    assert dist_copy2.delete().result() == []
def test_invalid_distributor_repo_id():
    """distributor's repo id being different from repo it's attached is invalid"""

    dist = Distributor(id="dist", type_id="yum_distributor", repo_id="repo")
    with pytest.raises(ValueError) as ex:
        repo = Repository(id="test_repo", distributors=[dist])

    assert "repo_id doesn't match for dist" in str(ex.value)
def test_delete_success(fast_poller, requests_mocker, client):
    """delete succeeds and returns spawned tasks"""

    repo = Repository(
        id="some-repo",
        distributors=[
            Distributor(id="dist1", type_id="type1", repo_id="some-repo"),
            Distributor(id="dist2", type_id="type2", repo_id="some-repo"),
        ],
    )
    repo._set_client(client)

    requests_mocker.delete(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/distributors/dist1/",
        json={"spawned_tasks": [{
            "task_id": "task1"
        }, {
            "task_id": "task2"
        }]},
    )

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/tasks/search/",
        json=[
            {
                "task_id": "task1",
                "state": "finished"
            },
            {
                "task_id": "task2",
                "state": "skipped"
            },
        ],
    )

    # It should succeed, with the tasks as retrieved from Pulp
    dist = repo.distributors[0]
    delete_dist = dist.delete()
    assert sorted(delete_dist) == [
        Task(id="task1", succeeded=True, completed=True),
        Task(id="task2", succeeded=True, completed=True),
    ]

    # And should now be detached
    with pytest.raises(DetachedException):
        dist.delete()
Esempio n. 19
0
def test_can_search_distributors_with_relative_url(client, requests_mocker):
    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/distributors/search/",
        json=[
            {
                "id": "yum_distributor",
                "distributor_type_id": "yum_distributor",
                "repo_id": "test_rpm",
                "config": {
                    "relative_url": "relative/path"
                },
            },
            {
                "id": "cdn_distributor",
                "distributor_type_id": "rpm_rsync_distributor",
                "config": {
                    "relative_url": "relative/path"
                },
            },
        ],
    )

    crit = Criteria.with_field("relative_url", Matcher.regex("relative/path"))
    distributors_f = client.search_distributor(crit)

    distributors = [dist for dist in distributors_f.result()]

    # distributor objects are returned
    assert sorted(distributors) == [
        Distributor(
            id="cdn_distributor",
            type_id="rpm_rsync_distributor",
            relative_url="relative/path",
        ),
        Distributor(
            id="yum_distributor",
            type_id="yum_distributor",
            repo_id="test_rpm",
            relative_url="relative/path",
        ),
    ]
    # api is called once
    assert requests_mocker.call_count == 1
Esempio n. 20
0
def test_search_distributor():
    controller = FakeController()

    dist1 = Distributor(id="yum_distributor",
                        type_id="yum_distributor",
                        repo_id="repo1")
    dist2 = Distributor(id="cdn_distributor",
                        type_id="rpm_rsync_distributor",
                        repo_id="repo1")
    repo1 = Repository(id="repo1", distributors=(dist1, dist2))

    controller.insert_repository(repo1)

    client = controller.client
    crit = Criteria.true()

    found = client.search_distributor(crit).result().data

    assert sorted(found) == [dist2, dist1]
Esempio n. 21
0
def test_can_search_distributor(client, requests_mocker):
    """search_distributor issues distributors/search POST request as expected."""
    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/distributors/search/",
        json=[
            {
                "id": "yum_distributor",
                "distributor_type_id": "yum_distributor",
                "repo_id": "test_rpm",
                "config": {
                    "relative_url": "relative/path"
                },
            },
            {
                "id": "cdn_distributor",
                "distributor_type_id": "rpm_rsync_distributor",
                "config": {
                    "relative_url": "relative/path"
                },
            },
        ],
    )

    distributors_f = client.search_distributor()
    distributors = [dist for dist in distributors_f.result().as_iter()]
    # distributor objects are returned
    assert sorted(distributors) == [
        Distributor(
            id="cdn_distributor",
            type_id="rpm_rsync_distributor",
            relative_url="relative/path",
        ),
        Distributor(
            id="yum_distributor",
            type_id="yum_distributor",
            repo_id="test_rpm",
            relative_url="relative/path",
        ),
    ]
    # api is called once
    assert requests_mocker.call_count == 1
def test_can_delete():
    """distributor.delete() with fake client removes distributor from fake data."""
    controller = FakeController()

    repo1 = Repository(
        id="repo1",
        distributors=[
            Distributor(id="dist1", type_id="type1", repo_id="repo1"),
            Distributor(id="dist2", type_id="type2", repo_id="repo1"),
        ],
    )

    controller.insert_repository(repo1)

    client = controller.client
    repo1 = client.get_repository("repo1")

    # Call to delete should succeed
    delete_f = repo1.distributors[0].delete()

    # The future should resolve successfully
    tasks = delete_f.result()

    # It should have returned at least one successful task.
    assert tasks
    for task in tasks:
        assert task.succeeded

    # The change should be reflected in the controller, with the
    # deleted distributor no longer present
    assert controller.repositories == [
        Repository(
            id="repo1",
            distributors=[
                Distributor(id="dist2", type_id="type2", repo_id="repo1")
            ],
        )
    ]
Esempio n. 23
0
def test_search_null_and():
    """Search with an empty AND gives an error."""
    controller = FakeController()

    dist1 = Distributor(id="yum_distributor",
                        type_id="yum_distributor",
                        repo_id="repo1")
    repo1 = Repository(id="repo1", distributors=[dist1])

    controller.insert_repository(repo1)

    client = controller.client
    crit = Criteria.and_()
    assert "Invalid AND in search query" in str(
        client.search_repository(crit).exception())
    assert "Invalid AND in search query" in str(
        client.search_distributor(crit).exception())
Esempio n. 24
0
def test_publish_broken_response(fast_poller, requests_mocker, client):
    """publish raises an exception if Pulp /publish/ responded with parseable
    JSON, but not of the expected structure
    """

    repo = YumRepository(
        id="some-repo",
        distributors=(Distributor(id="yum_distributor", type_id="yum_distributor"),),
    )
    repo.__dict__["_client"] = client

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        json={"spawned_tasks": ["oops, not a valid response"]},
    )

    publish_f = repo.publish()

    # It should raise some kind of exception due to the invalid spawned_tasks structure
    assert publish_f.exception()
def test_detached_noclient():
    """delete raises if called on a distributor without client"""
    with pytest.raises(DetachedException):
        Distributor(id="some-dist",
                    type_id="some-dist-type",
                    repo_id="some-repo").delete()
def test_detached_norepo(client):
    """delete raises if called on a distributor without repo"""
    with pytest.raises(DetachedException):
        dist = Distributor(id="some-dist", type_id="some-dist-type")
        dist._set_client(client)
        dist.delete()
Esempio n. 27
0
def test_publish_update_mappings(fast_poller, requests_mocker, client, caplog):
    """Publish on FileRepository will generate ud_file_release_mappings_2."""

    caplog.set_level(logging.INFO, "pubtools.pulplib")

    repo = FileRepository(
        id="some-repo",
        distributors=[
            Distributor(id="iso_distributor", type_id="iso_distributor")
        ],
    )
    repo.__dict__["_client"] = client

    # Force client to use a small page size so that we're able to verify
    # all pages end up handled.
    client._PAGE_SIZE = 3

    # Arrange for the repo to currently exist with some mappings.
    requests_mocker.get(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/",
        json={
            "id": "some-repo",
            "notes": {
                "ud_file_release_mappings_2":
                json.dumps(
                    # Define some mappings so there's a mix of data needing
                    # an update and data needing no update.
                    {
                        "1.0": [{
                            "filename": "file1",
                            "order": 3.0
                        }],
                        "3.0": [{
                            "filename": "file3",
                            "order": 1234
                        }],
                        "4.0": [{
                            "filename": "file4",
                            "order": 0
                        }],
                        "some-other-version": [{
                            "filename": "whatever-file",
                            "order": "abc",
                            "foo": "bar"
                        }],
                    })
            },
        },
    )

    # Make the repo have some units with the mapping-relevant fields. We use
    # two pages here to ensure that the code implements pagination.
    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/search/units/",
        [
            {
                # page 1
                "json": [
                    {
                        "metadata": {
                            "_content_type_id": "iso",
                            "name": "file1",
                            "size": 1,
                            "checksum":
                            "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411",
                            "pulp_user_metadata": {
                                "version": "1.0",
                                "display_order": 3.0,
                            },
                        }
                    },
                    {
                        "metadata": {
                            "_content_type_id":
                            "iso",
                            "name":
                            "file2",
                            "size":
                            1,
                            "checksum":
                            "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411",
                        }
                    },
                    {
                        "metadata": {
                            "_content_type_id": "iso",
                            "name": "file3",
                            "size": 1,
                            "checksum":
                            "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411",
                            "pulp_user_metadata": {
                                "version": "3.0"
                            },
                        }
                    },
                ]
            },
            {
                # page 2
                "json": [
                    {
                        "metadata": {
                            "_content_type_id": "iso",
                            "name": "file4",
                            "size": 1,
                            "checksum":
                            "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411",
                            "pulp_user_metadata": {
                                "version": "4.0",
                                "display_order": -2,
                            },
                        }
                    },
                    {
                        "metadata": {
                            "_content_type_id": "iso",
                            "name": "file5",
                            "size": 1,
                            "checksum":
                            "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411",
                            "pulp_user_metadata": {
                                "version": "1.0",
                                "display_order": 4.5,
                            },
                        }
                    },
                    {
                        "metadata": {
                            "_content_type_id": "iso",
                            "name": "file6",
                            "size": 1,
                            "checksum":
                            "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411",
                            "pulp_user_metadata": {
                                "version": "6.0"
                            },
                        }
                    },
                ]
            },
            {
                # page 3: nothing more
                "json": []
            },
        ],
    )

    # Allow for an update to the repository.
    requests_mocker.put(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/",
        json={})

    # It should publish as usual.
    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        json={"spawned_tasks": [{
            "task_id": "publish-task"
        }]},
    )

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/tasks/search/",
        json=[{
            "task_id": "publish-task",
            "state": "finished"
        }],
    )

    # It should have succeeded, with the publish task as retrieved from pulp
    assert sorted(repo.publish()) == [
        Task(id="publish-task", succeeded=True, completed=True)
    ]

    # Now let's have a look at what it updated.
    # The last operations are (update repo, start publish, await tasks),
    # so the update request should always be the 3rd last.
    req = requests_mocker.request_history[-3]

    # Should have been a PUT to the repo.
    assert req.url == "https://pulp.example.com/pulp/api/v2/repositories/some-repo/"
    assert req.method == "PUT"

    # It should have included this field in the delta...
    mapping_json = req.json()["delta"]["notes"]["ud_file_release_mappings_2"]

    # It should have been valid JSON
    mapping = json.loads(mapping_json)

    # It should be equal to this:
    assert mapping == {
        "1.0": [
            # This file wasn't changed
            {
                "filename": "file1",
                "order": 3.0
            },
            # This was added
            {
                "filename": "file5",
                "order": 4.5
            },
        ],
        # This wasn't touched because, although the repo has the file, it has no
        # defined order
        "3.0": [{
            "filename": "file3",
            "order": 1234
        }],
        # This was updated
        "4.0": [{
            "filename": "file4",
            "order": -2.0
        }],
        # This was added, with the entire version not previously defined.
        # Also, order field is omitted because none was in the data, but
        # the version and file still must be written.
        "6.0": [{
            "filename": "file6"
        }],
        # This is some unrelated junk which should be left alone during the
        # update process.
        "some-other-version": [{
            "filename": "whatever-file",
            "foo": "bar",
            "order": "abc"
        }],
    }

    # It should have logged that this happened
    assert "Updated ud_file_release_mappings_2 in some-repo" in caplog.messages
Esempio n. 28
0
def test_publish_update_mappings_noop(fast_poller, requests_mocker, client):
    """Publish on FileRepository does not do unnecessary repo updates."""
    repo = FileRepository(
        id="some-repo",
        distributors=[
            Distributor(id="iso_distributor", type_id="iso_distributor")
        ],
    )
    repo.__dict__["_client"] = client

    # Arrange for the repo to currently exist with up-to-date mappings.
    requests_mocker.get(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/",
        json={
            "id": "some-repo",
            "notes": {
                "ud_file_release_mappings_2":
                json.dumps({
                    "1.0": [
                        {
                            "filename": "file1",
                            "order": 3.0
                        },
                        {
                            "filename": "file2",
                            "order": 6.0
                        },
                    ],
                    "other": ["whatever"],
                })
            },
        },
    )

    # Make the repo have some units with the mapping-relevant fields.
    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/search/units/",
        json=[
            {
                "metadata": {
                    "_content_type_id": "iso",
                    "name": "file1",
                    "size": 1,
                    "checksum":
                    "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411",
                    "pulp_user_metadata": {
                        "version": "1.0",
                        "display_order": 3.0
                    },
                }
            },
            {
                "metadata": {
                    "_content_type_id": "iso",
                    "name": "file2",
                    "size": 1,
                    "checksum":
                    "cd293be6cea034bd45a0352775a219ef5dc7825ce55d1f7dae9762d80ce64411",
                    "pulp_user_metadata": {
                        "version": "1.0"
                    },
                }
            },
        ],
    )

    # It should NOT update the repository, so we don't register any PUT.

    # It should publish as usual.
    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        json={"spawned_tasks": [{
            "task_id": "publish-task"
        }]},
    )

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/tasks/search/",
        json=[{
            "task_id": "publish-task",
            "state": "finished"
        }],
    )

    # It should have succeeded, with the tasks as retrieved from Pulp
    assert sorted(repo.publish()) == [
        Task(id="publish-task", succeeded=True, completed=True)
    ]
def test_publish_distributors(fast_poller, requests_mocker, client):
    """publish succeeds and returns tasks from each applicable distributor"""
    repo = YumRepository(
        id="some-repo",
        distributors=(
            Distributor(id="yum_distributor", type_id="yum_distributor"),
            Distributor(id="other_distributor", type_id="other_distributor"),
            Distributor(id="cdn_distributor", type_id="rpm_rsync_distributor"),
        ),
    )
    repo.__dict__["_client"] = client

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        [
            {
                "json": {
                    "spawned_tasks": [{
                        "task_id": "task1"
                    }, {
                        "task_id": "task2"
                    }]
                }
            },
            {
                "json": {
                    "spawned_tasks": [{
                        "task_id": "task3"
                    }]
                }
            },
        ],
    )

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/tasks/search/",
        [
            {
                "json": [
                    {
                        "task_id": "task1",
                        "state": "finished"
                    },
                    {
                        "task_id": "task2",
                        "state": "skipped"
                    },
                ]
            },
            {
                "json": [{
                    "task_id": "task3",
                    "state": "finished"
                }]
            },
        ],
    )

    # It should have succeeded, with the tasks as retrieved from Pulp
    assert sorted(repo.publish()) == [
        Task(id="task1", succeeded=True, completed=True),
        Task(id="task2", succeeded=True, completed=True),
        Task(id="task3", succeeded=True, completed=True),
    ]

    # It should have first issued a request to publish yum_distributor
    req = requests_mocker.request_history
    assert (
        req[0].url ==
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/"
    )
    assert req[0].json() == {"id": "yum_distributor", "override_config": {}}

    # Then polled for resulting tasks to succeed
    assert req[1].url == "https://pulp.example.com/pulp/api/v2/tasks/search/"
    assert req[1].json() == {
        "criteria": {
            "filters": {
                "task_id": {
                    "$in": ["task1", "task2"]
                }
            }
        }
    }

    # Then published the next distributor
    assert (
        req[2].url ==
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/"
    )
    assert req[2].json() == {"id": "cdn_distributor", "override_config": {}}

    # Then waited for those tasks to finish too
    assert req[3].url == "https://pulp.example.com/pulp/api/v2/tasks/search/"
    assert req[3].json() == {
        "criteria": {
            "filters": {
                "task_id": {
                    "$in": ["task3"]
                }
            }
        }
    }

    # And there should have been no more requests
    assert len(req) == 4
def test_publish_origin_only(requests_mocker, client):
    """publish skips docker distributor if origin_only=True"""
    repo = ContainerImageRepository(
        id="some-repo",
        distributors=(
            Distributor(id="docker_web_distributor_name_cli",
                        type_id="docker_distributor_web"),
            Distributor(id="cdn_distributor",
                        type_id="docker_rsync_distributor"),
            Distributor(id="cdn_distributor_unprotected",
                        type_id="docker_rsync_distributor"),
        ),
    )
    repo.__dict__["_client"] = client

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/repositories/some-repo/actions/publish/",
        [
            {
                "json": {
                    "spawned_tasks": [{
                        "task_id": "task1"
                    }]
                }
            },
            {
                "json": {
                    "spawned_tasks": [{
                        "task_id": "task2"
                    }]
                }
            },
        ],
    )

    requests_mocker.post(
        "https://pulp.example.com/pulp/api/v2/tasks/search/",
        [
            {
                "json": [{
                    "task_id": "task1",
                    "state": "finished"
                }]
            },
            {
                "json": [{
                    "task_id": "task2",
                    "state": "finished"
                }]
            },
        ],
    )

    # It should have succeeded, with the tasks as retrieved from Pulp
    assert sorted(repo.publish(PublishOptions(origin_only=True))) == [
        Task(id="task1", succeeded=True, completed=True),
        Task(id="task2", succeeded=True, completed=True),
    ]

    req = requests_mocker.request_history
    publish_req = [r for r in req if r.url.endswith("/publish/")]

    # It should have triggered these distributors in this order
    ids = [r.json()["id"] for r in publish_req]
    assert ids == ["cdn_distributor", "cdn_distributor_unprotected"]

    # It should have triggered with content_units_only=True
    assert publish_req[-1].json()["override_config"]["content_units_only"]