Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added image tag option #204

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pyouroboros/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Config(object):
'PROMETHEUS_PORT', 'NOTIFIERS', 'REPO_USER', 'REPO_PASS', 'CLEANUP', 'RUN_ONCE', 'LATEST', 'CRON',
'INFLUX_URL', 'INFLUX_PORT', 'INFLUX_USERNAME', 'INFLUX_PASSWORD', 'INFLUX_DATABASE', 'INFLUX_SSL',
'INFLUX_VERIFY_SSL', 'DATA_EXPORT', 'SELF_UPDATE', 'LABEL_ENABLE', 'DOCKER_TLS', 'LABELS_ONLY',
'DRY_RUN', 'HOSTNAME', 'DOCKER_TLS_VERIFY', 'SWARM']
'DRY_RUN', 'HOSTNAME', 'DOCKER_TLS_VERIFY', 'SWARM', 'IMAGE_TAG']

hostname = environ.get('HOSTNAME')
interval = 300
Expand All @@ -22,6 +22,7 @@ class Config(object):
data_export = None
log_level = 'info'
latest = False
image_tag = None
cleanup = False
run_once = False
dry_run = False
Expand Down Expand Up @@ -112,6 +113,9 @@ def parse(self):

if self.interval < 30:
self.interval = 30

if self.latest:
self.image_tag = 'latest'

for option in ['docker_sockets', 'notifiers', 'monitor', 'ignore']:
if isinstance(getattr(self, option), str):
Expand Down
27 changes: 13 additions & 14 deletions pyouroboros/dockerclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,15 @@ def pull(self, image_object):
except IndexError:
self.logger.error('Malformed or missing tag. Skipping...')
raise ConnectionError
if self.config.latest and image.tags[0][-6:] != 'latest':

if self.config.image_tag:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i am not mistaken, image.tags[0] is ALWAYS the tag used to run the image. This is our design intentionally. Random tags make it an unreasonable automation and it might be better suited for you to use a shared tag as your run tag that has updates. This is all assuming that my initial statement is true

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not my experience. For me, it was the last tag that was running. I had to untag the others before updates worked. While that isn't a big deal, it's an attempt to make the behaviour less random and more deterministic / explicit.

Regardless, this is merely an extension to the 'latest' feature; if that exists, I don't see a reason why it wouldn't be made slightly more flexible. If you only have the option to access this feature with the 'latest' tag, you can only use this on a single environment, but in my use case, I would like to use it on two (development and staging).

I would in fact argue that setting an image tag makes it less random, as I don't think image.tags[0] is reliable in the sense that I couldn't find any documentation that specifies how it is supposed to work. In other words, there don't seem to be any guarantees its behaviour will be backwards compatible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image.tags[0] is not reliable with multiple tags (I have just tested). You are correct. but container.attrs['Config']['Image'] Gives the exact tag used to run and that IS what our goal was. Im going to make a new pr with the above change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please check 55fb7b1

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you of course. I do think it is inconsistent to leave in the 'latest' feature.

More importantly however, in your change, you did not address the neglected else in the pull method. The elif's are not exhaustive, causing an issue later on where the function returns None instead of raising an exception. I've seen this happen when trying to pull an image from gitlab.com; the unauthorized check didn't work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh im not a fan of latest existing at all. That is left from legacy code. Ill talk to the devs about removing it. As for the bug you mentioned, please capture the logs surrounding it so i can get more details and make an issue request for it and ill get it cleaned up :)

if ':' in tag:
split_tag = tag.split(':')
if len(split_tag) == 2:
if '/' not in split_tag[1]:
tag = split_tag[0]
else:
tag = ':'.join(split_tag[:-1])
tag = f'{tag}:latest'
split_tag = tag.rpartition(':')
if '/' not in split_tag[2]:
tag = split_tag[0]
tag = f'{tag}:{self.config.image_tag}'

self.logger.debug('Checking tag: %s', tag)
self.logger.debug('Pulling tag: %s', tag)
dirtycajunrice marked this conversation as resolved.
Show resolved Hide resolved
try:
if self.config.dry_run:
registry_data = self.client.images.get_registry_data(tag)
Expand All @@ -103,17 +101,17 @@ def pull(self, image_object):
raise ConnectionError
elif 'unauthorized' in str(e):
if self.config.dry_run:
self.logger.error('dry run : Upstream authentication issue while checking %s. See: '
self.logger.error('Dry run: Upstream authentication issue while checking %s. See: '
dirtycajunrice marked this conversation as resolved.
Show resolved Hide resolved
'https://github.com/docker/docker-py/issues/2225', tag)
raise ConnectionError
else:
self.logger.critical("Invalid Credentials. Exiting")
exit(1)
elif 'Client.Timeout' in str(e):
self.logger.critical("Couldn't find an image on docker.com for %s. Local Build?", image.tags[0])
self.logger.critical("Couldn't find an image on docker.com for %s. Local Build?", tag)
raise ConnectionError
elif ('pull access' or 'TLS handshake') in str(e):
self.logger.critical("Couldn't pull. Skipping. Error: %s", e)
else:
self.logger.critical("Couldn't pull image %s. Skipping. Error: %s", tag, e)
raise ConnectionError

def get_running(self):
Expand Down Expand Up @@ -185,13 +183,14 @@ def update(self):
try:
latest_image = self.pull(current_image)
except ConnectionError:
self.logger.error('Ignoring container %s due to connection error while pulling', container.name)
continue

if self.config.dry_run:
# Ugly hack for repo digest
repo_digest_id = current_image.attrs['RepoDigests'][0].split('@')[1]
if repo_digest_id != latest_image.id:
self.logger.info('dry run : %s would be updated', container.name)
self.logger.info('Dry run: %s would be updated', container.name)
continue

# If current running container is running latest image
Expand Down
3 changes: 3 additions & 0 deletions pyouroboros/ouroboros.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ def main():
docker_group.add_argument('-L', '--latest', default=Config.latest, dest='LATEST', action='store_true',
help='Check for latest image instead of pulling current tag')

docker_group.add_argument('-g', '--image-tag', default=Config.image_tag, dest='IMAGE_TAG',
help='Check for specified tag, regardless of what is being used')

docker_group.add_argument('-r', '--repo-user', default=Config.repo_user, dest='REPO_USER',
help='Private docker registry username\n'
'EXAMPLE: foo@bar.baz')
Expand Down