Merge "Always send versioned paths to manifests/repos"
This commit is contained in:
commit
bf9ddb9f9d
@ -35,6 +35,7 @@ class ReleaseValidator(BasicValidator):
|
||||
"Invalid network data: {0}".format(network),
|
||||
log_message=True
|
||||
)
|
||||
|
||||
if "orchestrator_data" in d:
|
||||
if not isinstance(d["orchestrator_data"], dict):
|
||||
raise errors.InvalidData(
|
||||
@ -68,6 +69,11 @@ class ReleaseValidator(BasicValidator):
|
||||
"No release operating system specified",
|
||||
log_message=True
|
||||
)
|
||||
if "orchestrator_data" not in d:
|
||||
raise errors.InvalidData(
|
||||
'No orchestrator_data specified', log_message=True
|
||||
)
|
||||
|
||||
if db().query(Release).filter_by(
|
||||
name=d["name"],
|
||||
version=d["version"]
|
||||
|
@ -106,8 +106,20 @@ def upload_fixture(fileobj, loader=None):
|
||||
except Exception:
|
||||
break
|
||||
|
||||
new_obj = obj['model']()
|
||||
# NOTE(ikalnitsly):
|
||||
# In order to add a release to Nailgun we have to fill two tables:
|
||||
# releases and release_orchestrator_data. By using former fixture
|
||||
# approach we can't do it, since the fixture is bond to only one
|
||||
# database model and can't deal with additional logic. Therefore
|
||||
# we need to use Nailgun's objects which know how to handle it.
|
||||
#
|
||||
# TODO(ikalnitsky):
|
||||
# Rewrite fixture logic - it must be simple and obvious.
|
||||
if obj['model'] is objects.Release.model:
|
||||
objects.Release.create(obj['fields'])
|
||||
continue
|
||||
|
||||
new_obj = obj['model']()
|
||||
fk_fields = {}
|
||||
for field, value in obj["fields"].iteritems():
|
||||
f = getattr(obj['model'], field)
|
||||
|
@ -1234,6 +1234,11 @@
|
||||
uri: "http://{{settings.MASTER_IP}}:8080/targetimages/centos_65_x86_64-boot.img.gz"
|
||||
format: "ext2"
|
||||
container: "gzip"
|
||||
orchestrator_data:
|
||||
puppet_manifests_source: "rsync://{MASTER_IP}:/puppet/{OPENSTACK_VERSION}/manifests/"
|
||||
puppet_modules_source: "rsync://{MASTER_IP}:/puppet/{OPENSTACK_VERSION}/modules/"
|
||||
repo_metadata:
|
||||
"{OPENSTACK_VERSION}": "http://{MASTER_IP}:8080/{OPENSTACK_VERSION}/centos/x86_64"
|
||||
- pk: 2
|
||||
extend: *base_release
|
||||
fields:
|
||||
@ -1257,3 +1262,8 @@
|
||||
uri: "http://{{settings.MASTER_IP}}:8080/targetimages/ubuntu_1204_amd64-boot.img.gz"
|
||||
format: "ext2"
|
||||
container: "gzip"
|
||||
orchestrator_data:
|
||||
puppet_manifests_source: "rsync://{MASTER_IP}:/puppet/{OPENSTACK_VERSION}/manifests/"
|
||||
puppet_modules_source: "rsync://{MASTER_IP}:/puppet/{OPENSTACK_VERSION}/modules/"
|
||||
repo_metadata:
|
||||
"{OPENSTACK_VERSION}": "http://{MASTER_IP}:8080/{OPENSTACK_VERSION}/ubuntu/x86_64 precise main"
|
||||
|
@ -24,7 +24,7 @@ from sqlalchemy import not_
|
||||
|
||||
from nailgun import consts
|
||||
|
||||
from nailgun.objects.serializers.release import ReleaseSerializer
|
||||
from nailgun.objects.serializers import release as release_serializer
|
||||
|
||||
from nailgun.db import db
|
||||
|
||||
@ -43,6 +43,9 @@ class ReleaseOrchestratorData(NailgunObject):
|
||||
#: SQLAlchemy model
|
||||
model = models.ReleaseOrchestratorData
|
||||
|
||||
#: Serializer for ReleaseOrchestratorData
|
||||
serializer = release_serializer.ReleaseOrchestratorDataSerializer
|
||||
|
||||
#: JSON schema
|
||||
schema = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
@ -84,13 +87,14 @@ class ReleaseOrchestratorData(NailgunObject):
|
||||
release = Release.get_by_uid(rendered_data['release_id'])
|
||||
context = {
|
||||
'MASTER_IP': settings.MASTER_IP,
|
||||
'OPENSTACK_VERSION': release.version,
|
||||
}
|
||||
'OPENSTACK_VERSION': release.version}
|
||||
|
||||
# render all the paths
|
||||
repo_metadata = {}
|
||||
for key, value in six.iteritems(rendered_data['repo_metadata']):
|
||||
rendered_data['repo_metadata'][key] = \
|
||||
cls.render_path(value, context)
|
||||
formatted_key = cls.render_path(key, context)
|
||||
repo_metadata[formatted_key] = cls.render_path(value, context)
|
||||
rendered_data['repo_metadata'] = repo_metadata
|
||||
|
||||
rendered_data['puppet_manifests_source'] = \
|
||||
cls.render_path(rendered_data.get(
|
||||
@ -115,7 +119,7 @@ class Release(NailgunObject):
|
||||
model = models.Release
|
||||
|
||||
#: Serializer for Release
|
||||
serializer = ReleaseSerializer
|
||||
serializer = release_serializer.ReleaseSerializer
|
||||
|
||||
#: Release JSON schema
|
||||
schema = {
|
||||
@ -220,41 +224,16 @@ class Release(NailgunObject):
|
||||
|
||||
@classmethod
|
||||
def update_orchestrator_data(cls, instance, orchestrator_data):
|
||||
for k in ["id", "release_id"]:
|
||||
orchestrator_data.pop(k, None)
|
||||
if orchestrator_data:
|
||||
if instance.orchestrator_data:
|
||||
ReleaseOrchestratorData.update(
|
||||
instance.orchestrator_data, orchestrator_data)
|
||||
else:
|
||||
orchestrator_data["release_id"] = instance.id
|
||||
ReleaseOrchestratorData.create(orchestrator_data)
|
||||
orchestrator_data.pop("id", None)
|
||||
orchestrator_data["release_id"] = instance.id
|
||||
|
||||
ReleaseOrchestratorData.update(
|
||||
instance.orchestrator_data, orchestrator_data)
|
||||
|
||||
@classmethod
|
||||
def get_orchestrator_data_dict(cls, instance):
|
||||
os = instance.operating_system.lower()
|
||||
default_orchestrator_data = {
|
||||
"repo_metadata": {
|
||||
"nailgun":
|
||||
settings.DEFAULT_REPO[os].format(
|
||||
MASTER_IP=settings.MASTER_IP),
|
||||
},
|
||||
"puppet_modules_source":
|
||||
settings.DEFAULT_PUPPET['modules'].format(
|
||||
MASTER_IP=settings.MASTER_IP),
|
||||
"puppet_manifests_source":
|
||||
settings.DEFAULT_PUPPET['manifests'].format(
|
||||
MASTER_IP=settings.MASTER_IP),
|
||||
}
|
||||
|
||||
return {
|
||||
"repo_metadata":
|
||||
instance.orchestrator_data.repo_metadata,
|
||||
"puppet_modules_source":
|
||||
instance.orchestrator_data.puppet_modules_source,
|
||||
"puppet_manifests_source":
|
||||
instance.orchestrator_data.puppet_manifests_source
|
||||
} if instance.orchestrator_data else default_orchestrator_data
|
||||
data = instance.orchestrator_data
|
||||
return ReleaseOrchestratorData.serializer.serialize(data)
|
||||
|
||||
@classmethod
|
||||
def is_deployable(cls, instance):
|
||||
|
@ -62,13 +62,6 @@ RABBITMQ:
|
||||
fake: "0"
|
||||
hostname: "127.0.0.1"
|
||||
|
||||
DEFAULT_PUPPET:
|
||||
modules: "rsync://{MASTER_IP}:/puppet/modules/"
|
||||
manifests: "rsync://{MASTER_IP}:/puppet/manifests/"
|
||||
DEFAULT_REPO:
|
||||
centos: "http://{MASTER_IP}:8080/centos/x86_64"
|
||||
ubuntu: "http://{MASTER_IP}:8080/ubuntu/x86_64 precise main"
|
||||
|
||||
PLUGINS_PATH: '/var/www/nailgun/plugins'
|
||||
PLUGINS_SLAVES_SCRIPTS_PATH: '/etc/fuel/plugins/{plugin_name}/'
|
||||
PLUGINS_REPO_URL: 'http://{master_ip}:8080/plugins/{plugin_name}/'
|
||||
|
@ -134,6 +134,7 @@ class Environment(object):
|
||||
'attributes_metadata': self.get_default_attributes_metadata(),
|
||||
'volumes_metadata': self.get_default_volumes_metadata(),
|
||||
'roles_metadata': self.get_default_roles_metadata(),
|
||||
'orchestrator_data': self.get_default_orchestrator_data(),
|
||||
}
|
||||
if kwargs:
|
||||
release_data.update(kwargs)
|
||||
@ -469,6 +470,21 @@ class Environment(object):
|
||||
sample_plugin.update(kwargs)
|
||||
return sample_plugin
|
||||
|
||||
def get_default_orchestrator_data(self, **kwargs):
|
||||
orchestrator_data = {
|
||||
'puppet_manifests_source':
|
||||
'rsync://127.0.0.1:/puppet/2014.2-6.0/manifests/',
|
||||
|
||||
'puppet_modules_source':
|
||||
'rsync://127.0.0.1:/puppet/2014.2-6.0/modules/',
|
||||
|
||||
'repo_metadata': {
|
||||
'2014.2-6.0': 'http://127.0.0.1:8080/2014.2-6.0/centos/x86_64'
|
||||
}
|
||||
}
|
||||
orchestrator_data.update(kwargs)
|
||||
return orchestrator_data
|
||||
|
||||
def upload_fixtures(self, fxtr_names):
|
||||
for fxtr_path in self.fxtr_paths_by_names(fxtr_names):
|
||||
with open(fxtr_path, "r") as fxtr_file:
|
||||
|
@ -1529,16 +1529,16 @@ class TestRepoAndPuppetDataSerialization(OrchestratorSerializerTestBase):
|
||||
self.assertEqual(
|
||||
fact['repo_metadata'],
|
||||
{
|
||||
'nailgun': 'http://127.0.0.1:8080/centos/x86_64'
|
||||
'2014.2-6.0': 'http://127.0.0.1:8080/2014.2-6.0/centos/x86_64'
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
fact['puppet_modules_source'],
|
||||
'rsync://127.0.0.1:/puppet/modules/'
|
||||
'rsync://127.0.0.1:/puppet/2014.2-6.0/modules/'
|
||||
)
|
||||
self.assertEqual(
|
||||
fact['puppet_manifests_source'],
|
||||
'rsync://127.0.0.1:/puppet/manifests/'
|
||||
'rsync://127.0.0.1:/puppet/2014.2-6.0/manifests/'
|
||||
)
|
||||
|
||||
def test_orch_data_w_replaced_deployment_info(self):
|
||||
|
@ -33,8 +33,10 @@ class TestPlugin(base.BaseTestCase):
|
||||
self.plugin = Plugin.create(self.plugin_metadata)
|
||||
self.env.create(
|
||||
cluster_kwargs={'mode': 'multinode'},
|
||||
release_kwargs={'version': '2014.2-6.0',
|
||||
'operating_system': 'Ubuntu'})
|
||||
release_kwargs={
|
||||
'version': '2014.2-6.0',
|
||||
'operating_system': 'Ubuntu',
|
||||
'orchestrator_data': self.env.get_default_orchestrator_data()})
|
||||
self.cluster = self.env.clusters[0]
|
||||
self.attr_plugin = attr_plugin.ClusterAttributesPlugin(self.plugin)
|
||||
self.env_config = self.env.get_default_plugin_env_config()
|
||||
|
@ -687,7 +687,8 @@ class TestReleaseOrchestratorData(BaseIntegrationTest):
|
||||
self.data = {
|
||||
'release_id': self.release.id,
|
||||
'repo_metadata': {
|
||||
'5': 'http://10.20.0.2:8080/{OPENSTACK_VERSION}/centos/x86_64',
|
||||
'{OPENSTACK_VERSION}':
|
||||
'http://10.20.0.2:8080/{OPENSTACK_VERSION}/centos/x86_64',
|
||||
},
|
||||
'puppet_manifests_source': 'rsync://10.20.0.2:/puppet/modules/',
|
||||
'puppet_modules_source': 'rsync://10.20.0.2:/puppet/manifests/',
|
||||
@ -695,7 +696,8 @@ class TestReleaseOrchestratorData(BaseIntegrationTest):
|
||||
instance = objects.ReleaseOrchestratorData.create(self.data)
|
||||
|
||||
self.assertEqual(instance.repo_metadata, {
|
||||
'5': 'http://10.20.0.2:8080/{0}/centos/x86_64'.format(
|
||||
self.release.version:
|
||||
'http://10.20.0.2:8080/{0}/centos/x86_64'.format(
|
||||
self.release.version)})
|
||||
self.assertEqual(
|
||||
instance.puppet_manifests_source,
|
||||
|
@ -36,7 +36,9 @@ class TestHandlers(BaseIntegrationTest):
|
||||
params=jsonutils.dumps({
|
||||
'name': 'Another test release',
|
||||
'version': '1.0',
|
||||
'operating_system': 'CentOS'
|
||||
'operating_system': 'CentOS',
|
||||
'orchestrator_data':
|
||||
self.env.get_default_orchestrator_data(),
|
||||
}),
|
||||
headers=self.default_headers
|
||||
)
|
||||
@ -80,7 +82,9 @@ class TestHandlers(BaseIntegrationTest):
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
'orchestrator_data':
|
||||
self.env.get_default_orchestrator_data(),
|
||||
}),
|
||||
headers=self.default_headers
|
||||
)
|
||||
@ -109,7 +113,9 @@ class TestHandlers(BaseIntegrationTest):
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
'orchestrator_data':
|
||||
self.env.get_default_orchestrator_data()
|
||||
}),
|
||||
headers=self.default_headers,
|
||||
expect_errors=True
|
||||
@ -161,7 +167,9 @@ class TestHandlers(BaseIntegrationTest):
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
'orchestrator_data':
|
||||
self.env.get_default_orchestrator_data()
|
||||
}),
|
||||
headers=self.default_headers
|
||||
)
|
||||
@ -190,7 +198,9 @@ class TestHandlers(BaseIntegrationTest):
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
'orchestrator_data':
|
||||
self.env.get_default_orchestrator_data(),
|
||||
}),
|
||||
headers=self.default_headers,
|
||||
expect_errors=True
|
||||
|
96
nailgun/nailgun/test/unit/test_release_validator.py
Normal file
96
nailgun/nailgun/test/unit/test_release_validator.py
Normal file
@ -0,0 +1,96 @@
|
||||
# Copyright 2014 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from nailgun.openstack.common import jsonutils
|
||||
|
||||
from nailgun.api.v1.validators.release import ReleaseValidator
|
||||
from nailgun.errors import errors
|
||||
from nailgun.test.base import BaseTestCase
|
||||
|
||||
|
||||
class TestReleaseValidator(BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestReleaseValidator, self).setUp()
|
||||
|
||||
self.release = {
|
||||
'name': 'Test Release',
|
||||
'version': '2014.2-6.0',
|
||||
'operating_system': 'CentOS',
|
||||
'orchestrator_data': {
|
||||
'puppet_manifests_source': 'path/to/manifests',
|
||||
'puppet_modules_source': 'path/to/modules',
|
||||
|
||||
'repo_metadata': {
|
||||
'repo': 'path/to/repo', }}}
|
||||
self.validator = ReleaseValidator
|
||||
|
||||
def get_release(self, release):
|
||||
return jsonutils.dumps(release)
|
||||
|
||||
def test_name_is_mandatory(self):
|
||||
self.release.pop('name')
|
||||
|
||||
self.assertRaisesRegexp(
|
||||
errors.InvalidData,
|
||||
'No release name specified',
|
||||
self.validator.validate,
|
||||
self.get_release(self.release))
|
||||
|
||||
def test_version_is_mandatory(self):
|
||||
self.release.pop('version')
|
||||
|
||||
self.assertRaisesRegexp(
|
||||
errors.InvalidData,
|
||||
'No release version specified',
|
||||
self.validator.validate,
|
||||
self.get_release(self.release))
|
||||
|
||||
def test_operating_system_is_mandatory(self):
|
||||
self.release.pop('operating_system')
|
||||
|
||||
self.assertRaisesRegexp(
|
||||
errors.InvalidData,
|
||||
'No release operating system specified',
|
||||
self.validator.validate,
|
||||
self.get_release(self.release))
|
||||
|
||||
def test_orchestrator_data_is_mandatory(self):
|
||||
self.release.pop('orchestrator_data')
|
||||
|
||||
self.assertRaisesRegexp(
|
||||
errors.InvalidData,
|
||||
'No orchestrator_data specified',
|
||||
self.validator.validate,
|
||||
self.get_release(self.release))
|
||||
|
||||
def test_orchestrator_data_must_be_a_dict(self):
|
||||
self.release['orchestrator_data'] = None
|
||||
|
||||
self.assertRaisesRegexp(
|
||||
errors.InvalidData,
|
||||
"'orchestrator_data' field must be a dict",
|
||||
self.validator.validate,
|
||||
self.get_release(self.release))
|
||||
|
||||
def test_orchestrator_data_required_keys(self):
|
||||
self.release['orchestrator_data'] = {}
|
||||
|
||||
self.assertRaisesRegexp(
|
||||
errors.InvalidData,
|
||||
"'orchestrator_data' doesn't have all required keys",
|
||||
self.validator.validate,
|
||||
self.get_release(self.release))
|
||||
|
||||
def test_default_are_good(self):
|
||||
self.validator.validate(self.get_release(self.release))
|
Loading…
Reference in New Issue
Block a user