def test_multiple(self) -> None: """ Multiple sidecars can exist at once. """ with DockerLoopbackVolume(size_megabytes=1) as first: with DockerLoopbackVolume(size_megabytes=1) as second: assert first.path != second.path
def clean() -> None: """ Remove containers, volumes and networks created by this tool. """ client = docker_client() filters = { 'label': [ '{key}={value}'.format( key=NODE_TYPE_LABEL_KEY, value=NODE_TYPE_LOOPBACK_SIDECAR_LABEL_VALUE, ), ], } loopback_sidecars = client.containers.list(filters=filters) for loopback_sidecar in loopback_sidecars: DockerLoopbackVolume.destroy(container=loopback_sidecar) node_filters = {'name': Docker().container_name_prefix} network_filters = {'name': Docker().container_name_prefix} node_containers = client.containers.list(filters=node_filters, all=True) for container in node_containers: container.stop() container.remove(v=True) networks = client.networks.list(filters=network_filters) for network in networks: network.remove()
def destroy_loopback_sidecar(name: str) -> None: """ Destroy a loopback sidecar. """ loopback_sidecars = loopback_sidecars_by_name(name=name) if not loopback_sidecars: message = 'Loopback sidecar "{name}" does not exist'.format( name=name, ) raise click.BadParameter(message) [loopback_sidecar] = loopback_sidecars with Halo(enabled=sys.stdout.isatty()): # type: ignore DockerLoopbackVolume.destroy(container=loopback_sidecar)
def destroy_loopback_sidecar(enable_spinner: bool, name: str) -> None: """ Destroy a loopback sidecar. """ loopback_sidecars = loopback_sidecars_by_name(name=name) if not loopback_sidecars: message = 'Loopback sidecar "{name}" does not exist'.format( name=name, ) raise click.BadParameter(message) [loopback_sidecar] = loopback_sidecars with Halo(enabled=enable_spinner): DockerLoopbackVolume.destroy(container=loopback_sidecar)
def test_destroy(self) -> None: """ The container and block device are destroyed. """ client = docker.from_env(version='auto') key = uuid.uuid4().hex value = uuid.uuid4().hex labels = {key: value} with DockerLoopbackVolume(size_megabytes=1, labels=labels) as device: filters = {'label': ['{key}={value}'.format(key=key, value=value)]} [existing_container] = client.containers.list(filters=filters) block_device_exists_cmd = ['lsblk', device.path] with pytest.raises(docker.errors.NotFound): existing_container.reload() new_container = client.containers.create( privileged=True, detach=True, image='centos:7', ) new_container.start() exit_code, output = new_container.exec_run(cmd=block_device_exists_cmd) new_container.stop() new_container.remove() assert exit_code != 0, output.decode()
def test_loopback(self) -> None: """ A block device is created which is accessible to multiple containers. """ client = docker.from_env(version='auto') with DockerLoopbackVolume(size_megabytes=1) as device: new_container = client.containers.create( privileged=True, detach=True, image='centos:7', ) new_container.start() try: block_device_exists_cmd = ['lsblk', device.path] exit_code, output = new_container.exec_run( cmd=block_device_exists_cmd, ) assert exit_code == 0, device.path + ': ' + output.decode() block_device_has_right_size = [ 'stat', '-f', '"%z"', device.path, ] exit_code, output = new_container.exec_run( cmd=block_device_has_right_size, ) assert exit_code == 0, device.path + ': ' + output.decode() assert output == '1048576' finally: new_container.stop() new_container.remove()
def test_loopback(self, size_megabytes: int) -> None: """ A block device is created which is accessible to multiple containers. """ client = docker.from_env(version='auto') container = client.containers.create( privileged=True, detach=True, image='centos:7', entrypoint=['/bin/sleep', 'infinity'], ) with DockerLoopbackVolume(size_megabytes=size_megabytes) as device: container.start() path = device.path block_device_exists = ['lsblk', path] block_device_has_right_size = ['blockdev', '--getsize64', path] exists_exit_code, exists_output = container.exec_run( cmd=block_device_exists, ) size_exit_code, size_output = container.exec_run( cmd=block_device_has_right_size, ) container.stop() container.remove() assert exists_exit_code == 0, path + ': ' + exists_output.decode() assert size_exit_code == 0, path + ': ' + size_output.decode() expected_output = str(1024 * 1024 * size_megabytes) assert size_output.decode().strip() == expected_output
def test_labels(self) -> None: """ The given labels are applied to the new container. """ client = docker.from_env(version='auto') key = uuid.uuid4().hex value = uuid.uuid4().hex labels = {key: value} with DockerLoopbackVolume(size_megabytes=1, labels=labels): filters = {'label': ['{key}={value}'.format(key=key, value=value)]} [existing_container] = client.containers.list(filters=filters) for key, value in labels.items(): assert existing_container.labels[key] == value
def create_loopback_sidecar(size: int, name: str) -> None: """ Create a loopback sidecar. A loopback sidecar provides a loopback device that points to a (unformatted) block device. """ if loopback_sidecars_by_name(name=name): message = 'Loopback sidecar "{name}" already exists'.format( name=name, ) raise click.BadParameter(message) loopback_volume = DockerLoopbackVolume( size_megabytes=size, labels={ NODE_TYPE_LABEL_KEY: NODE_TYPE_LOOPBACK_SIDECAR_LABEL_VALUE, SIDECAR_NAME_LABEL_KEY: name, }, ) click.echo(loopback_volume.path)