示例#1
0
def test_create_conflict():
    manager = ResourceManager()
    manager.inventory = {
        "already-exists": {
            "name": "already-exists",
            "type": "shell"
        }
    }
    with pytest.raises(ResourceAlreadyExistsError):
        manager.create("already-exists", "type-doesnt-matter")
示例#2
0
def test_create_missing_required():
    with pytest.raises(ResourceError) as exc:
        # SSH requires host.
        with patch("reproman.interface.create.get_manager",
                   return_value=ResourceManager()):
            create("somessh", "ssh", [])
    assert "host" in str(exc.value)
示例#3
0
def test_create_start_stop(tmpdir):
    tmpdir = str(tmpdir)
    inventory_file = op.join(tmpdir, "inventory.yml")
    rm = ResourceManager(inventory_file)

    # Simple smoke test.  We can't easily test the effects of start/stop with
    # shell because those the start and stop methods are noops.
    with patch("reproman.interface.create.get_manager", return_value=rm):
        main(["create", "-t", "shell", "testshell"])

    with open(inventory_file) as ifh:
        inventory = yaml.safe_load(ifh)
    assert inventory["testshell"]["status"] == "available"

    with patch("reproman.interface.start.get_manager", return_value=rm):
        main(["start", "testshell"])

    with patch("reproman.interface.stop.get_manager", return_value=rm):
        main(["stop", "testshell"])

    with patch("reproman.interface.delete.get_manager", return_value=rm):
        main(["delete", "--skip-confirmation", "testshell"])

    with open(inventory_file) as ifh:
        inventory = yaml.safe_load(ifh)
    assert "testshell" not in inventory
示例#4
0
def test_create_includes_config(tmpdir):
    tmpdir = str(tmpdir)
    manager = ResourceManager(op.join(tmpdir, "inventory.yml"))
    # We load items from the config.
    config_file = op.join(tmpdir, "reproman.cfg")
    with open(config_file, "w") as cfh:
        cfh.write("[ssh]\nhost = myhost\n")
    config = ConfigManager(filenames=[config_file], load_default=False)
    with patch.object(manager, "config_manager", config):
        with patch.object(manager, "factory") as factory:
            manager.create("myssh", "ssh")
            factory.assert_called_with({
                "host": "myhost",
                "name": "myssh",
                "type": "ssh"
            })
示例#5
0
def test_resource_manager_save(tmpdir):
    inventory = op.join(str(tmpdir), "subdir", "inventory.yml")
    manager = ResourceManager(inventory)
    manager.inventory = {
        "plain": {
            "name": "plain",
            "type": "foo-type",
            "id": "foo_id"
        },
        "with-secret": {
            "name": "with-secret",
            "type": "bar-type",
            "secret_access_key": "SECRET",
            "id": "bar_id"
        },
        "null-id": {
            "name": "null-id",
            "id": None,
            "type": "baz-type"
        }
    }
    manager.save_inventory()
    assert op.exists(inventory)
    with open(inventory) as fh:
        content = fh.read()
    assert "plain" in content
    assert "with-secret" in content
    assert "SECRET" not in content
    assert "null-id" not in content

    # Reload that inventory, add another item, and save again.
    manager_reborn = ResourceManager(inventory)
    manager_reborn.inventory["added"] = {
        "name": "added",
        "type": "added-type",
        "id": "added-id"
    }
    manager_reborn.save_inventory()
    with open(inventory) as fh:
        content_reread = fh.read()
    for line in content:
        assert line in content_reread
    assert "added" in content_reread
示例#6
0
 def __call__(backends=None):
     backends = backends or ResourceManager._discover_types()
     for backend, cls in get_resource_classes(backends):
         param_doc = "\n".join([
             "  {}: {}".format(p, pdoc)
             for p, pdoc in sorted(get_resource_backends(cls).items())
         ])
         if param_doc:
             out = "Backend parameters for '{}'\n{}".format(
                 backend, param_doc)
         else:
             out = "No backend parameters for '{}'".format(backend)
         print(out)
示例#7
0
def get_resource_classes(names=None):
    for name in names or ResourceManager._discover_types():
        try:
            module = import_module('reproman.resource.{}'.format(name))
        except ImportError as exc:
            import difflib
            known = ResourceManager._discover_types()
            suggestions = difflib.get_close_matches(name, known)
            lgr.warning(
                "Failed to import resource %s: %s. %s: %s", name, exc_str(exc),
                "Similar backends" if suggestions else "Known backends",
                ', '.join(suggestions or known))
            continue

        class_name = ''.join([token.capitalize() for token in name.split('_')])
        cls = getattr(module, class_name)
        if issubclass(cls, Resource):
            yield name, cls
        else:
            lgr.debug(
                "Skipping %s.%s because it is not a Resource. "
                "Consider moving away", module, class_name)
示例#8
0
def test_delete_interface():
    """
    Test deleting a resource.
    """

    with patch('docker.Client') as client, \
        patch('reproman.resource.ResourceManager._save'), \
        patch('reproman.resource.ResourceManager._get_inventory') as get_inventory, \
        swallow_logs(new_level=logging.DEBUG) as log:

        client.return_value = MagicMock(
            containers=lambda all: [{
                'Id': '326b0fdfbf838',
                'Names': ['/my-resource'],
                'State': 'running'
            }])

        get_inventory.return_value = {
            "my-resource": {
                "status": "running",
                "engine_url": "tcp://127.0.0.1:2375",
                "type": "docker-container",
                "name": "my-resource",
                "id": "326b0fdfbf838"
            }
        }

        args = ['delete', '--skip-confirmation', 'my-resource']
        with patch("reproman.interface.delete.get_manager",
                   return_value=ResourceManager()):
            main(args)

        calls = [
            call(base_url='tcp://127.0.0.1:2375'),
            call().remove_container(
                {
                    'State': 'running',
                    'Id': '326b0fdfbf838',
                    'Names': ['/my-resource']
                },
                force=True)
        ]
        client.assert_has_calls(calls, any_order=True)

        assert_in('Deleted the environment my-resource', log.lines)
示例#9
0
def test_create_interface():
    """
    Test creating an environment
    """

    with patch('docker.Client') as client, \
        patch('reproman.resource.ResourceManager.save_inventory'), \
        patch('reproman.resource.ResourceManager._get_inventory'), \
        swallow_logs(new_level=logging.DEBUG) as log:

        client.return_value = MagicMock(
            containers=lambda all: [],
            pull=lambda repository, stream: [
                b'{ "status" : "status 1", "progress" : "progress 1" }',
                b'{ "status" : "status 2", "progress" : "progress 2" }'
            ],
            create_container=lambda name, image, stdin_open, tty, command: {
                'Id': '18b31b30e3a5'
            }
        )

        args = ['create',
                '--resource-type', 'docker-container',
                '--backend', 'engine_url=tcp://127.0.0.1:2376',
                '--',
                'my-test-resource'
        ]
        with patch("reproman.interface.create.get_manager",
                   return_value=ResourceManager()):
            main(args)

        calls = [
            call(base_url='tcp://127.0.0.1:2376'),
            call().start(container='18b31b30e3a5')
        ]
        client.assert_has_calls(calls, any_order=True)

        assert_in("status 1 progress 1", log.lines)
        assert_in("status 2 progress 2", log.lines)
        assert_in("Created the environment my-test-resource", log.lines)
示例#10
0
def test_login_interface():
    """
    Test logging into an environment
    """

    with patch('docker.Client') as client, \
        patch('reproman.resource.ResourceManager._get_inventory') as get_inventory, \
        patch('dockerpty.start'), \
        swallow_logs(new_level=logging.DEBUG) as log:

        client.return_value = MagicMock(
            containers=lambda all: [{
                'Id': '18b31b30e3a5',
                'Names': ['/my-test-resource'],
                'State': 'running'
            }], )

        get_inventory.return_value = {
            "my-test-resource": {
                "status": "running",
                "engine_url": "tcp://127.0.0.1:2375",
                "type": "docker-container",
                "name": "my-test-resource",
                "id": "18b31b30e3a5"
            }
        }

        args = ['login', 'my-test-resource']

        with patch("reproman.interface.login.get_manager",
                   return_value=ResourceManager()):
            main(args)

        assert client.call_count == 1

        calls = [call(base_url='tcp://127.0.0.1:2375')]
        client.assert_has_calls(calls, any_order=True)

        assert_in("Opening TTY connection to docker container.", log.lines)
示例#11
0
def test_get_resources_empty_resref():
    with pytest.raises(ValueError):
        ResourceManager().get_resource("")
示例#12
0
 def fixture(tmpdir_factory):
     path = str(tmpdir_factory.mktemp("rmanager").join("inventory"))
     manager = ResourceManager(path)
     for name, kwargs in resources.items():
         manager.create(name, **kwargs)
     return manager
示例#13
0
def test_resource_manager_factory_missing_type():
    with pytest.raises(MissingConfigError):
        ResourceManager.factory({})
示例#14
0
def test_get_resources():
    manager = ResourceManager()
    manager.inventory = {
        "myshell": {
            "name": "myshell",
            "type": "shell",
            "id": "0-myshell-id"
        },
        "ambig-id0": {
            "name": "ambig-id0",
            "type": "shell",
            "id": "ambig-id"
        },
        "ambig-id1": {
            "name": "ambig-id1",
            "type": "shell",
            "id": "ambig-id"
        },
        "id-name-same": {
            "name": "id-name-same",
            "type": "shell",
            "id": "0-uniq-id"
        },
        "same-id": {
            "name": "same-id",
            "type": "shell",
            "id": "id-name-same"
        },
        "00": {
            "name": "00",
            "type": "shell",
            "id": "00s-id"
        },
        "partial-is-other": {
            "name": "partial-is-other",
            "type": "shell",
            "id": "00-rest-of-id"
        }
    }

    with pytest.raises(ResourceError):
        manager.get_resource("not there")

    resource_uniq = manager.get_resource("myshell")
    assert resource_uniq.name == "myshell"
    # We can get the same resource by ID.
    assert manager.get_resource(resource_uniq.id).name == resource_uniq.name
    # ... or by a unique partial prefix match on ID.
    assert manager.get_resource("0-m").name == resource_uniq.name

    with pytest.raises(MultipleResourceMatches):
        manager.get_resource("ambig-id")

    # We get an exception if both if there is an name-ID collision...
    with pytest.raises(MultipleResourceMatches):
        manager.get_resource("id-name-same")
    # ... but we can disambiguate with resref_type.
    assert manager.get_resource("id-name-same", "name").id == "0-uniq-id"
    assert manager.get_resource("id-name-same", "id").id == "id-name-same"

    # Ambiguous prefix match on ID:
    with pytest.raises(MultipleResourceMatches):
        manager.get_resource("0-")

    # When a name matches the partial ID match, we prefer the name.
    assert manager.get_resource("00").id == "00s-id"
    # We could do partial match on ID if we specify resref type, though.
    assert manager.get_resource("00-r", "id").id == "00-rest-of-id"

    # ... but it still must be unique.
    with pytest.raises(MultipleResourceMatches):
        assert manager.get_resource("00", "id")
示例#15
0
def test_resource_manager_inventory_undefined():
    with pytest.raises(MissingConfigError):
        ResourceManager("")
示例#16
0
def test_resource_manager_empty_init(tmpdir):
    inventory = op.join(str(tmpdir), "inventory.yml")
    manager = ResourceManager(inventory)
    assert not manager.inventory
示例#17
0
def test_resource_manager_factory_unkown():
    with pytest.raises(ResourceError):
        ResourceManager.factory({"type": "not really a type"})