Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
params=httpize(params),
headers=headers,
data=data,
timeout=timeout,
chunked=chunked,
)
except asyncio.TimeoutError:
raise
if (response.status // 100) in [4, 5]:
what = await response.read()
content_type = response.headers.get("content-type", "")
response.close()
if content_type == "application/json":
raise DockerError(response.status, json.loads(what.decode("utf8")))
else:
raise DockerError(response.status, {"message": what.decode("utf8")})
return response
async def test_auto_pull_digest_when_missing(agent, mocker):
behavior = AutoPullBehavior.DIGEST
inspect_mock = AsyncMock(
side_effect=DockerError(status=404,
data={'message': 'Simulated missing image'}))
mocker.patch.object(agent.docker.images, 'inspect', new=inspect_mock)
pull = await agent.check_image(imgref, query_digest, behavior)
assert pull
inspect_mock.assert_called_with(imgref.canonical)
async def test_run_container_with_missing_image(docker):
name = "python:latest"
try:
await docker.images.delete(name)
except DockerError as e:
if e.status == 404:
pass # already missing, pass
else:
raise
# should automatically pull the image
container = await docker.containers.run(
config={"Cmd": ["-c", "print('hello')"], "Entrypoint": "python", "Image": name}
)
await _validate_hello(container)
else:
log.info('preparing the Docker image for krunner extractor...')
extractor_archive = pkg_resources.resource_filename(
'ai.backend.runner', 'krunner-extractor.img.tar.xz')
with lzma.open(extractor_archive, 'rb') as reader:
proc = await asyncio.create_subprocess_exec(
*['docker', 'load'], stdin=reader)
if (await proc.wait() != 0):
raise RuntimeError('loading krunner extractor image has failed!')
log.info('checking krunner-env for {}...', distro)
do_create = False
try:
vol = DockerVolume(docker, volume_name)
await vol.show()
except DockerError as e:
if e.status == 404:
do_create = True
if do_create:
log.info('populating {} volume version {}',
volume_name, current_version)
await docker.volumes.create({
'Name': volume_name,
'Driver': 'local',
})
archive_path = Path(pkg_resources.resource_filename(
f'ai.backend.krunner.{distro_name}',
f'krunner-env.{distro}.{arch}.tar.xz')).resolve()
extractor_path = Path(pkg_resources.resource_filename(
'ai.backend.runner',
'krunner-extractor.sh')).resolve()
proc = await asyncio.create_subprocess_exec(*[
async def docker_call_retry(f, *args, **kwargs):
delay = 0.1
while True:
try:
return await f(*args, **kwargs)
except DockerError as e:
# 408 request timeout, 503 service unavailable
if e.status == 408 or e.status == 503:
log.exception('in docker call, retrying')
# DockerError(500, 'Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
# DockerError(500, 'error creating overlay mount to /var/lib/docker/overlay2/545a1337742e0292d9ed197b06fe900146c85ab06e468843cd0461c3f34df50d/merged: device or resource busy'
elif e.status == 500 and ("request canceled while waiting for connection" in e.message or
re.match("error creating overlay mount.*device or resource busy", e.message)):
log.exception('in docker call, retrying')
else:
raise
except asyncio.TimeoutError:
log.exception('in docker call, retrying')
# exponentially back off, up to (expected) max of 30s
t = delay * random.random()
await asyncio.sleep(t)
delay = min(delay * 2, 60.0)
async def api_impl(container_id):
try:
container = DockerContainer(ctx.agent.docker, id=container_id)
ret = await container.stats(stream=False) # TODO: cache
except RuntimeError as e:
msg = str(e.args[0]).lower()
if 'event loop is closed' in msg or 'session is closed' in msg:
return None
raise
except (DockerError, aiohttp.ClientError):
short_cid = container._id[:7]
log.warning(f'cannot read stats: Docker stats API error for {short_cid}.')
return None
else:
# API returned successfully but actually the result may be empty!
if ret is None or not isinstance(ret, dict):
return None
if ret['preread'].startswith('0001-01-01'):
return None
mem_cur_bytes = nmget(ret, 'memory_stats.usage', 0)
io_read_bytes = 0
io_write_bytes = 0
for item in nmget(ret, 'blkio_stats.io_service_bytes_recursive', []):
if item['op'] == 'Read':
io_read_bytes += item['value']
elif item['op'] == 'Write':
class DockerError(Exception):
def __init__(self, status, data, *args):
super().__init__(*args)
self.status = status
self.message = data["message"]
def __repr__(self):
return "DockerError({self.status}, {self.message!r})".format(self=self)
def __str__(self):
return "DockerError({self.status}, {self.message!r})".format(self=self)
class DockerContainerError(DockerError):
def __init__(self, status, data, container_id, *args):
super().__init__(status, data, *args)
self.container_id = container_id
def __repr__(self):
return (
"DockerContainerError("
"{self.status}, {self.message!r}, "
"{self.container_id!r})"
).format(self=self)
def __str__(self):
return (
"DockerContainerError("
"{self.status}, {self.message!r}, "
"{self.container_id!r})"
async def demo(docker):
try:
await docker.images.inspect('alpine:latest')
except DockerError as e:
if e.status == 404:
await docker.pull('alpine:latest')
else:
print('Error retrieving alpine:latest image.')
return
config = {
# "Cmd": ["/bin/ash", "-c", "sleep 1; echo a; sleep 1; echo a; sleep 1; echo a; sleep 1; echo x"],
"Cmd": ["/bin/ash"],
"Image": "alpine:latest",
"AttachStdin": True,
"AttachStdout": True,
"AttachStderr": True,
"Tty": False,
"OpenStdin": True,
"StdinOnce": True,
async def run(self, config, *, name=None):
"""
Create and start a container.
If container.start() will raise an error the exception will contain
a `container_id` attribute with the id of the container.
"""
try:
container = await self.create(config, name=name)
except DockerError as err:
# image not find, try pull it
if err.status == 404 and "Image" in config:
await self.docker.pull(config["Image"])
container = await self.create(config, name=name)
else:
raise err
try:
await container.start()
except DockerError as err:
raise DockerContainerError(
err.status, {"message": err.message}, container["id"]
)
return container