Skip to content

Commit

Permalink
Ensure a tag is present in ImageStream
Browse files Browse the repository at this point in the history
  • Loading branch information
lcarva committed Dec 19, 2016
1 parent 45827a3 commit a723c22
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 20 deletions.
15 changes: 15 additions & 0 deletions inputs/image_stream_tag.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"kind": "ImageStreamTag",
"apiVersion": "v1",
"metadata": {
"name": "{{IMAGE_STREAM_ID}}:{{TAG_ID}}"
},
"tag": {
"name": "{{TAG_ID}}",
"from": {
"kind": "DockerImage",
"name": "{{REPOSITORY}}:{{TAG_ID}}"
},
"importPolicy": {}
}
}
28 changes: 28 additions & 0 deletions osbs/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,34 @@ def get_serviceaccount_tokens(self, username="~"):
def get_image_stream_tag(self, tag_id):
return self.os.get_image_stream_tag(tag_id)

@osbsapi
def put_image_stream_tag(self, tag_id, tag):
"""Create or modify ImageStreamTag object
:param tag_id: str, name of ImageStreamTag prefixed by name of
corresponding ImageStream, imagestream:tag
:param tag: dict, definition of ImageStreamTag
:return: API response
"""
return self.os.put_image_stream_tag(tag_id, tag)

@osbsapi
def ensure_image_stream_tag(self, stream, tag_name, scheduled=False):
"""Ensures the tag is monitored in ImageStream
:param stream: dict, ImageStream object
:param tag_name: str, name of tag to check, without name of
ImageStream as prefix
:param scheduled: bool, if True, importPolicy.scheduled will be
set to True in ImageStreamTag
:return: bool, whether or not modifications were performed
"""
img_stream_tag_file = os.path.join(self.os_conf.get_build_json_store(),
'image_stream_tag.json')
tag_template = json.load(open(img_stream_tag_file))
return self.os.ensure_image_stream_tag(stream, tag_name, tag_template,
scheduled)

@osbsapi
def get_image_stream(self, stream_id):
return self.os.get_image_stream(stream_id)
Expand Down
49 changes: 49 additions & 0 deletions osbs/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,55 @@ def get_image_stream_tag(self, tag_id):
check_response(response)
return response

def put_image_stream_tag(self, tag_id, tag):
url = self._build_url("imagestreamtags/%s" % tag_id)
response = self._put(url, data=json.dumps(tag),
headers={"Content-Type": "application/json"})
check_response(response)
return response

def ensure_image_stream_tag(self, stream, tag_name, tag_template,
scheduled=False):
stream_id = stream['metadata']['name']
insecure = (stream['metadata']
.get('annotations', {})
.get('openshift.io/image.insecureRepository')
== 'true')
repo = stream['spec']['dockerImageRepository']
tag_id = '{0}:{1}'.format(stream_id, tag_name)

changed = False
try:
tag = self.get_image_stream_tag(tag_id).json()
logger.debug('image stream tag found: %s', tag_id)
except OsbsResponseException as exc:
if exc.status_code != 404:
raise

logger.debug('image stream tag NOT found: %s', tag_id)

tag = tag_template
tag['metadata']['name'] = tag_id
tag['tag']['name'] = tag_name
tag['tag']['from']['name'] = '{0}:{1}'.format(repo, tag_name)
changed = True

if insecure != tag['tag']['importPolicy'].get('insecure', False):
tag['tag']['importPolicy']['insecure'] = insecure
logger.debug('setting importPolicy.insecure to: %s', insecure)
changed = True

if scheduled != tag['tag']['importPolicy'].get('scheduled', False):
tag['tag']['importPolicy']['scheduled'] = scheduled
logger.debug('setting importPolicy.scheduled to: %s', scheduled)
changed = True

if changed:
logger.debug('modifying image stream tag: %s', tag_id)
self.put_image_stream_tag(tag_id, tag)

return changed

def get_image_stream(self, stream_id):
url = self._build_url("imagestreams/%s" % stream_id)
response = self._get(url)
Expand Down
80 changes: 60 additions & 20 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from types import GeneratorType

from flexmock import flexmock
from textwrap import dedent
import json
from pkg_resources import parse_version
import os
Expand Down Expand Up @@ -443,13 +444,13 @@ def test_get_compression_extension(self, tmpdir, compress, args,
inner.truncate()

with NamedTemporaryFile(mode='wt') as fp:
fp.write("""
[general]
build_json_dir = {build_json_dir}
[default]
openshift_url = /
registry_uri = registry.example.com
""".format(build_json_dir=str(tmpdir)))
fp.write(dedent("""\
[general]
build_json_dir = {build_json_dir}
[default]
openshift_url = /
registry_uri = registry.example.com
""".format(build_json_dir=str(tmpdir))))
fp.flush()
config = Configuration(fp.name)
osbs = OSBS(config, config)
Expand All @@ -463,19 +464,19 @@ def test_get_compression_extension(self, tmpdir, compress, args,
def test_build_image(self):
build_image = 'registry.example.com/buildroot:2.0'
with NamedTemporaryFile(mode='wt') as fp:
fp.write("""
[general]
build_json_dir = {build_json_dir}
[default]
openshift_url = /
sources_command = /bin/true
vendor = Example, Inc
registry_uri = registry.example.com
build_host = localhost
authoritative_registry = localhost
distribution_scope = private
build_image = {build_image}
""".format(build_json_dir='inputs', build_image=build_image))
fp.write(dedent("""\
[general]
build_json_dir = {build_json_dir}
[default]
openshift_url = /
sources_command = /bin/true
vendor = Example, Inc
registry_uri = registry.example.com
build_host = localhost
authoritative_registry = localhost
distribution_scope = private
build_image = {build_image}
""".format(build_json_dir='inputs', build_image=build_image)))
fp.flush()
config = Configuration(fp.name)
osbs = OSBS(config, config)
Expand Down Expand Up @@ -993,3 +994,42 @@ def test_get_image_stream_tag(self):
response = osbs.get_image_stream_tag(name)
ref = response.json()['image']['dockerImageReference']
assert ref == 'spam:maps'

def test_put_image_stream_tag(self):
config = Configuration()
osbs = OSBS(config, config)

tag_id = 'buildroot:latest'
tag = '{"spam": "maps"}'
(flexmock(osbs.os)
.should_receive('put_image_stream_tag')
.with_args(tag_id, tag)
.once()
.and_return('eggs')
)

response = osbs.put_image_stream_tag(tag_id, tag)
assert response == 'eggs'

def test_ensure_image_stream_tag(self):
with NamedTemporaryFile(mode='wt') as fp:
fp.write(dedent("""\
[general]
build_json_dir = {build_json_dir}
""".format(build_json_dir='inputs')))
fp.flush()
config = Configuration(fp.name)
osbs = OSBS(config, config)

stream = {'type': 'stream'}
tag_name = 'latest'
scheduled = False
(flexmock(osbs.os)
.should_receive('ensure_image_stream_tag')
.with_args(stream, tag_name, dict, scheduled)
.once()
.and_return('eggs')
)

response = osbs.ensure_image_stream_tag(stream, tag_name, scheduled)
assert response == 'eggs'
145 changes: 145 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
of the BSD license. See the LICENSE file for details.
"""
from flexmock import flexmock
from textwrap import dedent
import pycurl
import six
import time
Expand Down Expand Up @@ -227,3 +228,147 @@ def test_get_multiple_build_config_by_labels(self, openshift):
with pytest.raises(OsbsException) as exc:
openshift.get_build_config_by_labels(label_selectors)
assert str(exc.value).startswith('More than one build config found')

def test_put_image_stream_tag(self, openshift):
tag_name = 'spam'
tag_id = 'maps:' + tag_name
mock_data = {
'kind': 'ImageStreamTag',
'apiVersion': 'v1',
'tag': {
'name': tag_name
}
}

expected_url = openshift._build_url('imagestreamtags/' + tag_id)
(flexmock(openshift)
.should_receive("_put")
.with_args(expected_url, data=json.dumps(mock_data),
headers={"Content-Type": "application/json"})
.once()
.and_return(HttpResponse(200, {}, json.dumps(mock_data))))

openshift.put_image_stream_tag(tag_id, mock_data)

def _make_tag_template(self):
# TODO: Just read from inputs folder
return json.loads(dedent('''\
{
"kind": "ImageStreamTag",
"apiVersion": "v1",
"metadata": {
"name": "{{IMAGE_STREAM_ID}}:{{TAG_ID}}"
},
"tag": {
"name": "{{TAG_ID}}",
"from": {
"kind": "DockerImage",
"name": "{{REPOSITORY}}:{{TAG_ID}}"
},
"importPolicy": {}
}
}
'''))

@pytest.mark.parametrize('existing_scheduled', (True, False, None))
@pytest.mark.parametrize('existing_insecure', (True, False, None))
@pytest.mark.parametrize('expected_scheduled', (True, False))
@pytest.mark.parametrize(('s_annotations', 'expected_insecure'), (
({'openshift.io/image.insecureRepository': 'true'}, True),
({'openshift.io/image.insecureRepository': 'false'}, False),
({}, False),
(None, False),
))
@pytest.mark.parametrize('status_code', (200, 404, 500))
def test_ensure_image_stream_tag(self,
existing_scheduled,
existing_insecure,
expected_scheduled,
s_annotations,
expected_insecure,
status_code,
openshift):
stream_name = 'spam'
stream_repo = 'some.registry.com/spam'
stream = {
'metadata': {'name': stream_name},
'spec': {'dockerImageRepository': stream_repo}
}
if s_annotations is not None:
stream['metadata']['annotations'] = s_annotations

tag_name = 'maps'
tag_id = '{0}:{1}'.format(stream_name, tag_name)

expected_url = openshift._build_url('imagestreamtags/' +
tag_id)

def verify_image_stream_tag(*args, **kwargs):
data = json.loads(kwargs['data'])

assert (bool(data['tag']['importPolicy'].get('insecure'))
== expected_insecure)
assert (bool(data['tag']['importPolicy'].get('scheduled'))
== expected_scheduled)

# Also verify new image stream tags are created properly.
if status_code == 404:
assert data['metadata']['name'] == tag_id
assert data['tag']['name'] == tag_name
assert (data['tag']['from']['name']
== '{0}:{1}'.format(stream_repo, tag_name))


return HttpResponse(200, {}, json.dumps('{}'))

expected_change = False
expected_error = status_code == 500

mock_response = '{}'

if status_code == 200:
existing_image_stream_tag = {'tag': {'importPolicy': {}}}

if existing_insecure is not None:
existing_image_stream_tag['tag']['importPolicy']['insecure'] = \
existing_insecure

if existing_scheduled is not None:
existing_image_stream_tag['tag']['importPolicy']['scheduled'] = \
existing_scheduled

mock_response = json.dumps(existing_image_stream_tag)

if expected_insecure != bool(existing_insecure) or \
expected_scheduled != bool(existing_scheduled):
expected_change = True

elif status_code == 404:
expected_change = True

(flexmock(openshift)
.should_receive("_get")
.with_args(expected_url)
.once()
.and_return(HttpResponse(status_code, {}, mock_response))
)

if expected_change:
(flexmock(openshift)
.should_receive("_put")
.with_args(expected_url, data=str,
headers={"Content-Type": "application/json"})
.replace_with(verify_image_stream_tag)
.once()
)

if expected_error:
with pytest.raises(OsbsResponseException):
openshift.ensure_image_stream_tag(
stream, tag_name, self._make_tag_template(), expected_scheduled)

else:
assert (openshift.ensure_image_stream_tag(
stream, tag_name, self._make_tag_template() ,expected_scheduled)
== expected_change)

0 comments on commit a723c22

Please sign in to comment.