Basic labels support

Adds basic labels support to the registry code (V2), and the API. Note that this does not yet add any UI related support.
This commit is contained in:
Joseph Schorr 2016-07-18 18:20:00 -04:00
parent 427070b453
commit 608ffd9663
24 changed files with 907 additions and 36 deletions

View file

@ -65,6 +65,8 @@ from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserMana
from endpoints.api.secscan import RepositoryImageSecurity
from endpoints.api.suconfig import (SuperUserRegistryStatus, SuperUserConfig, SuperUserConfigFile,
SuperUserCreateInitialSuperUser)
from endpoints.api.manifest import RepositoryManifestLabels, ManageRepositoryManifestLabel
try:
app.register_blueprint(api_bp, url_prefix='/api')
@ -1765,6 +1767,15 @@ class TestDeleteRepository(ApiTestCase):
RepositoryActionCount.create(repository=repository,
date=datetime.datetime.now() - datetime.timedelta(days=5), count=6)
# Create some labels.
tag_manifest = model.tag.load_tag_manifest(ADMIN_ACCESS_USER, 'complex', 'prod')
model.label.create_manifest_label(tag_manifest, 'foo', 'bar', 'manifest')
model.label.create_manifest_label(tag_manifest, 'foo', 'baz', 'manifest')
model.label.create_manifest_label(tag_manifest, 'something', '{}', 'api',
media_type_name='application/json')
model.label.create_manifest_label(tag_manifest, 'something', '{"some": "json"}', 'manifest')
# Delete the repository.
with check_transitive_deletes():
self.deleteResponse(Repository, params=dict(repository=self.COMPLEX_REPO))
@ -3941,6 +3952,150 @@ class TestSuperUserKeyManagement(ApiTestCase):
self.assertEquals('whazzup!?', json['approval']['notes'])
class TestRepositoryManifestLabels(ApiTestCase):
def test_basic_labels(self):
self.login(ADMIN_ACCESS_USER)
# Find the manifest digest for the prod tag in the complex repo.
tag_manifest = model.tag.load_tag_manifest(ADMIN_ACCESS_USER, 'complex', 'prod')
repository = ADMIN_ACCESS_USER + '/complex'
# Check the existing labels on the complex repo, which should be empty
json = self.getJsonResponse(RepositoryManifestLabels,
params=dict(repository=repository, manifestref=tag_manifest.digest))
self.assertEquals(0, len(json['labels']))
# Add some labels to the manifest.
with assert_action_logged('manifest_label_add'):
label1 = self.postJsonResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest),
data=dict(key='hello', value='world',
media_type='text/plain'),
expected_code=201)
with assert_action_logged('manifest_label_add'):
label2 = self.postJsonResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest),
data=dict(key='hi', value='there',
media_type='text/plain'),
expected_code=201)
with assert_action_logged('manifest_label_add'):
label3 = self.postJsonResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest),
data=dict(key='hello', value='someone',
media_type='application/json'),
expected_code=201)
# Ensure we have *3* labels
json = self.getJsonResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest))
self.assertEquals(3, len(json['labels']))
self.assertNotEquals(label2['label']['id'], label1['label']['id'])
self.assertNotEquals(label3['label']['id'], label1['label']['id'])
self.assertNotEquals(label2['label']['id'], label3['label']['id'])
self.assertEquals('text/plain', label1['label']['media_type'])
self.assertEquals('text/plain', label2['label']['media_type'])
self.assertEquals('application/json', label3['label']['media_type'])
# Delete a label.
with assert_action_logged('manifest_label_delete'):
self.deleteResponse(ManageRepositoryManifestLabel,
params=dict(repository=repository,
manifestref=tag_manifest.digest,
labelid=label1['label']['id']))
# Ensure the label is gone.
json = self.getJsonResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest))
self.assertEquals(2, len(json['labels']))
# Check filtering.
json = self.getJsonResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest,
filter='hello'))
self.assertEquals(1, len(json['labels']))
def test_prefixed_labels(self):
self.login(ADMIN_ACCESS_USER)
# Find the manifest digest for the prod tag in the complex repo.
tag_manifest = model.tag.load_tag_manifest(ADMIN_ACCESS_USER, 'complex', 'prod')
repository = ADMIN_ACCESS_USER + '/complex'
self.postJsonResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest),
data=dict(key='com.dockers.whatever', value='pants',
media_type='text/plain'),
expected_code=201)
self.postJsonResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest),
data=dict(key='my.cool.prefix.for.my.label', value='value',
media_type='text/plain'),
expected_code=201)
def test_add_invalid_media_type(self):
self.login(ADMIN_ACCESS_USER)
tag_manifest = model.tag.load_tag_manifest(ADMIN_ACCESS_USER, 'complex', 'prod')
repository = ADMIN_ACCESS_USER + '/complex'
self.postResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest),
data=dict(key='hello', value='world', media_type='some/invalid'),
expected_code=400)
def test_add_invalid_key(self):
self.login(ADMIN_ACCESS_USER)
tag_manifest = model.tag.load_tag_manifest(ADMIN_ACCESS_USER, 'complex', 'prod')
repository = ADMIN_ACCESS_USER + '/complex'
# Try to add an empty label key.
self.postResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest),
data=dict(key='', value='world'),
expected_code=400)
# Try to add an invalid label key.
self.postResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest),
data=dict(key='invalid___key', value='world'),
expected_code=400)
# Try to add a label key in a reserved namespace.
self.postResponse(RepositoryManifestLabels,
params=dict(repository=repository,
manifestref=tag_manifest.digest),
data=dict(key='io.docker.whatever', value='world'),
expected_code=400)
class TestSuperUserManagement(ApiTestCase):
def test_get_user(self):
self.login(ADMIN_ACCESS_USER)