launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #11017
[Merge] lp:~jtv/maas/disable-pserv-api into lp:maas
Jeroen T. Vermeulen has proposed merging lp:~jtv/maas/disable-pserv-api into lp:maas with lp:~jtv/maas/kill-cobblerclient as a prerequisite.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~jtv/maas/disable-pserv-api/+merge/119854
With Cobbler being removed, we're also eradicating the provisioning service API. I'm trying to do this in stages because the branches get massive, and because we get weird import problems somewhere along the line that I'd much rather deal with in relative isolation.
We have a middleware that monitors component failures. It was only monitoring Cobbler profiles, but I kept it in its remaining empty form — I suspect that we'll want to revive it for use in the Cobbler-less setup. Even if we don't, this branch is big enough without that additional change!
One of the remaining tasks is to remove the pserv API itself. That's for another branch. Oh, there's many more branches on the way for this.
Jeroen
--
https://code.launchpad.net/~jtv/maas/disable-pserv-api/+merge/119854
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/maas/disable-pserv-api into lp:maas.
=== modified file 'src/maasserver/middleware.py'
--- src/maasserver/middleware.py 2012-06-26 09:47:31 +0000
+++ src/maasserver/middleware.py 2012-08-16 07:39:19 +0000
@@ -28,7 +28,6 @@
from django.conf import settings
from django.contrib import messages
-from django.core.cache import cache
from django.core.exceptions import (
PermissionDenied,
ValidationError,
@@ -103,34 +102,11 @@
return None
-PROFILES_CHECK_DONE_KEY = 'profile-check-done'
-
-# The profiles check done by check_profiles_cached is only done at most once
-# every PROFILE_CHECK_DELAY seconds for efficiency.
-PROFILE_CHECK_DELAY = 2 * 60
-
-
-def check_profiles_cached():
- """Check Cobbler's profiles. The check is actually done at most once every
- PROFILE_CHECK_DELAY seconds for performance reasons.
- """
- # Avoid circular imports.
- from maasserver.provisioning import check_profiles
- if not cache.get(PROFILES_CHECK_DONE_KEY, False):
- # Mark the profile check as done beforehand as the actual check
- # might raise an exception.
- cache.set(PROFILES_CHECK_DONE_KEY, True, PROFILE_CHECK_DELAY)
- check_profiles()
-
-
-def clear_profiles_check_cache():
- """Force a profile check next time the MAAS server is accessed."""
- cache.delete(PROFILES_CHECK_DONE_KEY)
-
-
class ExternalComponentsMiddleware:
- """This middleware performs checks for external components (right
- now only Cobbler is checked) at regular intervals.
+ """Middleware check external components at regular intervals.
+
+ Right now nothing is checked, because Cobbler was the only component
+ we checked, and we just ditched it.
"""
def process_request(self, request):
# This middleware hijacks the request to perform checks. Any
@@ -138,7 +114,8 @@
# disturbing the handling of the request. Proper error reporting
# should be handled in the check method itself.
try:
- check_profiles_cached()
+ # TODO: Components checks here.
+ pass
except Exception:
pass
return None
=== modified file 'src/maasserver/models/node.py'
--- src/maasserver/models/node.py 2012-08-10 14:55:04 +0000
+++ src/maasserver/models/node.py 2012-08-16 07:39:19 +0000
@@ -131,13 +131,6 @@
}
-def get_papi():
- """Return a provisioning server API proxy."""
- # Avoid circular imports.
- from maasserver.provisioning import get_provisioning_api_proxy
- return get_provisioning_api_proxy()
-
-
class NodeManager(Manager):
"""A utility to manage the collection of Nodes."""
=== modified file 'src/maasserver/provisioning.py'
--- src/maasserver/provisioning.py 2012-08-14 11:03:43 +0000
+++ src/maasserver/provisioning.py 2012-08-16 07:39:19 +0000
@@ -11,40 +11,23 @@
__metaclass__ = type
__all__ = [
- 'check_profiles',
- 'get_provisioning_api_proxy',
'present_detailed_user_friendly_fault',
'ProvisioningProxy',
]
from functools import partial
-import itertools
-from logging import getLogger
from textwrap import dedent
from urllib import urlencode
import xmlrpclib
from django.conf import settings
-from django.db.models.signals import (
- post_delete,
- post_save,
- )
-from django.dispatch import receiver
-from django.utils.safestring import mark_safe
from maasserver.components import (
COMPONENT,
discard_persistent_error,
register_persistent_error,
)
-from maasserver.enum import (
- ARCHITECTURE_CHOICES,
- NODE_STATUS,
- )
+from maasserver.enum import NODE_STATUS
from maasserver.exceptions import ExternalComponentException
-from maasserver.models import (
- MACAddress,
- Node,
- )
from maasserver.utils import absolute_reverse
from provisioningserver.enum import PSERV_FAULT
import yaml
@@ -301,37 +284,6 @@
return connection
-def get_provisioning_api_proxy():
- """Return a proxy to the Provisioning API.
-
- If ``PSERV_URL`` is not set, we attempt to return a handle to a fake proxy
- implementation. This will not be available in a packaged version of MAAS,
- in which case an error is raised.
- """
- if settings.USE_REAL_PSERV:
- # Use a real provisioning server. This requires PSERV_URL to be
- # set.
- xmlrpc_transport = ProvisioningTransport(use_datetime=True)
- xmlrpc_proxy = xmlrpclib.ServerProxy(
- settings.PSERV_URL, transport=xmlrpc_transport, allow_none=True)
- else:
- # Create a fake. The code that provides the testing fake is not
- # available in an installed production system, so import it only
- # when a fake is requested.
- try:
- from maasserver.testing import get_fake_provisioning_api_proxy
- except ImportError:
- getLogger('maasserver').error(
- "Could not import fake provisioning proxy. "
- "This may mean you're trying to run tests, or have set "
- "USE_REAL_PSERV to False, on an installed MAAS. "
- "Don't do either.")
- raise
- xmlrpc_proxy = get_fake_provisioning_api_proxy()
-
- return ProvisioningProxy(xmlrpc_proxy)
-
-
def compose_cloud_init_preseed(token):
"""Compose the preseed value for a node in any state but Commissioning."""
credentials = urlencode({
@@ -393,127 +345,3 @@
return compose_commissioning_preseed(token)
else:
return compose_cloud_init_preseed(token)
-
-
-def name_arch_in_cobbler_style(architecture):
- """Give architecture name as used in cobbler.
-
- MAAS uses Ubuntu-style architecture names, notably including "amd64"
- which in Cobbler terms is "x86_64."
-
- :param architecture: An architecture name (e.g. as produced by MAAS).
- :type architecture: basestring
- :return: An architecture name in Cobbler style.
- :rtype: unicode
- """
- conversions = {
- 'amd64': 'x86_64',
- 'i686': 'i386',
- }
- if isinstance(architecture, bytes):
- architecture = architecture.decode('ascii')
- return conversions.get(architecture, architecture)
-
-
-def check_profiles():
- """Check that Cobbler has profiles defined for all the profiles used by
- MAAS.
-
- This should no longer be relevant, since Cobbler is being removed.
- """
- all_profiles = get_all_profile_names()
- papi = get_provisioning_api_proxy()
- existing_profiles = set(papi.get_profiles_by_name(all_profiles))
- missing_profiles = set(all_profiles) - existing_profiles
- if len(missing_profiles) != 0:
- # Some profiles are missing: display a persistent component
- # error.
- register_persistent_error(
- COMPONENT.IMPORT_PXE_FILES,
- mark_safe(
- """
- Some Cobbler system profiles are missing.
-
- Cobbler has been removed as a component of MAAS; this should
- no longer matter.
- """))
-
-
-def get_all_profile_names():
- """Return all the names of the profiles used by MAAS."""
- architectures = {arch[0] for arch in ARCHITECTURE_CHOICES}
- commissioning = {True, False}
- product = itertools.product(architectures, commissioning)
- profiles = [
- get_profile_name(architecture, commissioning)
- for architecture, commissioning in product]
- return profiles
-
-
-def get_profile_name(architecture, commissioning=False):
- """Return the profile name for a given architecture and whether the node
- is commissioning or not."""
- cobbler_arch = name_arch_in_cobbler_style(architecture)
- profile = "maas-%s-%s" % ("precise", cobbler_arch)
- if commissioning:
- profile += "-commissioning"
- return profile
-
-
-def select_profile_for_node(node):
- """Select which profile a node should be configured for."""
- assert node.architecture, "Node's architecture is not known."
- commissioning = node.status == NODE_STATUS.COMMISSIONING
- return get_profile_name(node.architecture, commissioning)
-
-
-@receiver(post_save, sender=Node)
-def provision_post_save_Node(sender, instance, created, **kwargs):
- """Create or update nodes in the provisioning server."""
- papi = get_provisioning_api_proxy()
- profile = select_profile_for_node(instance)
- power_type = instance.get_effective_power_type()
- preseed_data = compose_preseed(instance)
- papi.add_node(
- instance.system_id, instance.hostname,
- profile, power_type, preseed_data)
-
- # When the node is allocated this must not modify the netboot_enabled
- # parameter. The node, once it has booted and installed itself, asks the
- # provisioning server to disable netbooting. If this were to enable
- # netbooting again, the node would reinstall itself the next time it
- # booted. However, netbooting must be enabled at the point the node is
- # allocated so that the first install goes ahead, hence why it is set for
- # all other statuses... with one exception; retired nodes are never
- # netbooted.
- if instance.status != NODE_STATUS.ALLOCATED:
- netboot_enabled = instance.status not in (
- NODE_STATUS.DECLARED, NODE_STATUS.RETIRED)
- delta = {"netboot_enabled": netboot_enabled}
- papi.modify_nodes({instance.system_id: delta})
-
-
-def set_node_mac_addresses(node):
- """Update the Node's MAC addresses in the provisioning server."""
- mac_addresses = [mac.mac_address for mac in node.macaddress_set.all()]
- deltas = {node.system_id: {"mac_addresses": mac_addresses}}
- get_provisioning_api_proxy().modify_nodes(deltas)
-
-
-@receiver(post_save, sender=MACAddress)
-def provision_post_save_MACAddress(sender, instance, created, **kwargs):
- """Create or update MACs in the provisioning server."""
- set_node_mac_addresses(instance.node)
-
-
-@receiver(post_delete, sender=Node)
-def provision_post_delete_Node(sender, instance, **kwargs):
- """Delete nodes in the provisioning server."""
- papi = get_provisioning_api_proxy()
- papi.delete_nodes_by_name([instance.system_id])
-
-
-@receiver(post_delete, sender=MACAddress)
-def provision_post_delete_MACAddress(sender, instance, **kwargs):
- """Delete MACs in the provisioning server."""
- set_node_mac_addresses(instance.node)
=== modified file 'src/maasserver/testing/tests/test_module.py'
--- src/maasserver/testing/tests/test_module.py 2012-06-12 14:08:19 +0000
+++ src/maasserver/testing/tests/test_module.py 2012-08-16 07:39:19 +0000
@@ -18,19 +18,14 @@
HttpResponse,
HttpResponseRedirect,
)
-from maasserver import provisioning
from maasserver.testing import (
extract_redirect,
reload_object,
reload_objects,
)
from maasserver.testing.factory import factory
-from maasserver.testing.testcase import (
- TestCase,
- TestModelTestCase,
- )
+from maasserver.testing.testcase import TestModelTestCase
from maasserver.testing.tests.models import TestModel
-from provisioningserver.testing import fakeapi
# Horrible kludge. Works around a bug where delete() does not work on
# test models when using nose. Without this, running the tests in this
@@ -42,43 +37,6 @@
TestModel._meta.get_all_related_objects()
-class TestTestCase(TestCase):
- """Tests for `TestCase`."""
-
- def test_patched_in_fake_papi(self):
- # TestCase.setUp() patches in a fake provisioning API so that we can
- # observe what the signal handlers are doing.
- papi_fake = provisioning.get_provisioning_api_proxy()
- self.assertIsInstance(papi_fake, provisioning.ProvisioningProxy)
- self.assertIsInstance(
- papi_fake.proxy, fakeapi.FakeSynchronousProvisioningAPI)
- # The fake has some limited, automatically generated, sample
- # data. This is required for many tests to run. First there is a
- # sample distro.
- self.assertEqual(1, len(papi_fake.distros))
- [distro_name] = papi_fake.distros
- expected_distros = {
- distro_name: {
- 'initrd': 'initrd',
- 'kernel': 'kernel',
- 'name': distro_name,
- },
- }
- self.assertEqual(expected_distros, papi_fake.distros)
- # Second there is a sample profile, referring to the distro.
- self.assertEqual(1, len(papi_fake.profiles))
- [profile_name] = papi_fake.profiles
- expected_profiles = {
- profile_name: {
- 'distro': distro_name,
- 'name': profile_name,
- },
- }
- self.assertEqual(expected_profiles, papi_fake.profiles)
- # There are no nodes.
- self.assertEqual({}, papi_fake.nodes)
-
-
class TestHelpers(TestModelTestCase):
"""Test helper functions."""
=== modified file 'src/maasserver/tests/test_middleware.py'
--- src/maasserver/tests/test_middleware.py 2012-04-27 12:38:18 +0000
+++ src/maasserver/tests/test_middleware.py 2012-08-16 07:39:19 +0000
@@ -17,17 +17,11 @@
import logging
from django.contrib.messages import constants
-from django.core.cache import cache
from django.core.exceptions import (
PermissionDenied,
ValidationError,
)
from django.test.client import RequestFactory
-from maasserver import (
- components,
- middleware as middleware_module,
- provisioning,
- )
from maasserver.exceptions import (
ExternalComponentException,
MAASAPIException,
@@ -36,13 +30,9 @@
)
from maasserver.middleware import (
APIErrorsMiddleware,
- check_profiles_cached,
- clear_profiles_check_cache,
ErrorsMiddleware,
ExceptionLoggerMiddleware,
ExceptionMiddleware,
- ExternalComponentsMiddleware,
- PROFILES_CHECK_DONE_KEY,
)
from maasserver.testing import extract_redirect
from maasserver.testing.factory import factory
@@ -204,80 +194,6 @@
self.assertThat(logfile, FileContains(matcher=Contains(error_text)))
-class ExternalComponentsMiddlewareTest(TestCase):
-
- def patch_papi_get_profiles_by_name(self, method):
- self.patch(components, '_PERSISTENT_ERRORS', {})
- papi = provisioning.get_provisioning_api_proxy()
- self.patch(papi.proxy, 'get_profiles_by_name', method)
-
- def test_middleware_calls_check_profiles_cached(self):
- calls = []
- self.patch(
- middleware_module, "check_profiles_cached",
- lambda: calls.append(1))
- middleware = ExternalComponentsMiddleware()
- response = middleware.process_request(None)
- self.assertIsNone(response)
- self.assertEqual(1, len(calls))
-
- def test_check_profiles_cached_sets_cache_key(self):
- def return_all_profiles(profiles):
- return profiles
- self.patch_papi_get_profiles_by_name(return_all_profiles)
-
- check_profiles_cached()
- self.assertTrue(cache.get(PROFILES_CHECK_DONE_KEY, False))
-
- def test_check_profiles_cached_sets_cache_key_if_exception_raised(self):
- # The cache key PROFILES_CHECK_DONE_KEY is set to True even if
- # the call to papi.get_profiles_by_name raises an exception.
- def raise_exception(profiles):
- raise Exception()
- self.patch_papi_get_profiles_by_name(raise_exception)
- try:
- check_profiles_cached()
- except Exception:
- pass
- self.assertTrue(cache.get(PROFILES_CHECK_DONE_KEY, False))
-
- def test_check_profiles_cached_does_nothing_if_cache_key_set(self):
- # If the cache key PROFILES_CHECK_DONE_KE is set to True
- # the call to check_profiles_cached is silent.
- def raise_exception(profiles):
- raise Exception()
- cache.set(PROFILES_CHECK_DONE_KEY, True)
- self.patch_papi_get_profiles_by_name(raise_exception)
- check_profiles_cached()
- # No exception, get_profiles_by_name has not been called.
-
- def test_clear_profiles_check_cache_deletes_PROFILES_CHECK_DONE_KEY(self):
- cache.set(PROFILES_CHECK_DONE_KEY, factory.getRandomString())
- self.assertTrue(cache.get(PROFILES_CHECK_DONE_KEY, False))
- clear_profiles_check_cache()
- self.assertFalse(cache.get(PROFILES_CHECK_DONE_KEY, False))
-
- def test_middleware_returns_none_if_exception_raised(self):
- def raise_exception(profiles):
- raise Exception()
-
- self.patch_papi_get_profiles_by_name(raise_exception)
- middleware = ExternalComponentsMiddleware()
- request = fake_request(factory.getRandomString())
- response = middleware.process_request(request)
- self.assertIsNone(response)
-
- def test_middleware_does_not_catch_keyboardinterrupt_exception(self):
- def raise_exception(profiles):
- raise KeyboardInterrupt()
-
- self.patch_papi_get_profiles_by_name(raise_exception)
- middleware = ExternalComponentsMiddleware()
- request = fake_request(factory.getRandomString())
- self.assertRaises(
- KeyboardInterrupt, middleware.process_request, request)
-
-
class ErrorsMiddlewareTest(LoggedInTestCase):
def test_error_middleware_ignores_GET_requests(self):
=== modified file 'src/maasserver/tests/test_node.py'
--- src/maasserver/tests/test_node.py 2012-08-10 14:55:04 +0000
+++ src/maasserver/tests/test_node.py 2012-08-16 07:39:19 +0000
@@ -33,7 +33,6 @@
)
from maasserver.models.node import NODE_TRANSITIONS
from maasserver.models.user import create_auth_token
-from maasserver.provisioning import get_provisioning_api_proxy
from maasserver.testing import reload_object
from maasserver.testing.factory import factory
from maasserver.testing.testcase import TestCase
@@ -674,31 +673,6 @@
self.celery.tasks[0]['kwargs']['mac'],
))
- def test_start_nodes_sets_commissioning_profile(self):
- # Starting up a node should always set a profile. Here we test
- # that a commissioning profile was set for nodes in the
- # commissioning status.
- user = factory.make_user()
- node = factory.make_node(
- set_hostname=True, status=NODE_STATUS.COMMISSIONING, owner=user)
- factory.make_mac_address(node=node)
- output = Node.objects.start_nodes([node.system_id], user)
- self.assertItemsEqual([node], output)
- profile = get_provisioning_api_proxy().nodes[node.system_id]['profile']
- self.assertEqual('maas-precise-i386-commissioning', profile)
-
- def test_start_nodes_doesnt_set_commissioning_profile(self):
- # Starting up a node should always set a profile. Complement the
- # above test to show that a different profile can be set.
- user = factory.make_user()
- node = self.make_node(user)
- factory.make_mac_address(node=node)
- output = Node.objects.start_nodes([node.system_id], user)
-
- self.assertItemsEqual([node], output)
- profile = get_provisioning_api_proxy().nodes[node.system_id]['profile']
- self.assertEqual('maas-precise-i386', profile)
-
def test_start_nodes_uses_default_power_type_if_not_node_specific(self):
# If the node has a power_type set to POWER_TYPE.DEFAULT,
# NodeManager.start_node(this_node) should use the default
=== modified file 'src/maasserver/tests/test_provisioning.py'
--- src/maasserver/tests/test_provisioning.py 2012-08-14 10:54:37 +0000
+++ src/maasserver/tests/test_provisioning.py 2012-08-16 07:39:19 +0000
@@ -12,43 +12,15 @@
__metaclass__ = type
__all__ = []
-from abc import ABCMeta
-from base64 import b64decode
from xmlrpclib import Fault
-from maasserver import (
- components,
- provisioning,
- )
-from maasserver.components import (
- COMPONENT,
- get_persistent_errors,
- register_persistent_error,
- )
-from maasserver.enum import (
- ARCHITECTURE,
- NODE_AFTER_COMMISSIONING_ACTION,
- NODE_STATUS,
- NODE_STATUS_CHOICES,
- )
-from maasserver.exceptions import (
- ExternalComponentException,
- MAASAPIException,
- )
-from maasserver.models import Node
+from maasserver.enum import NODE_STATUS
from maasserver.provisioning import (
- check_profiles,
- compose_cloud_init_preseed,
- compose_commissioning_preseed,
compose_preseed,
DETAILED_PRESENTATIONS,
- get_all_profile_names,
- get_profile_name,
- name_arch_in_cobbler_style,
present_detailed_user_friendly_fault,
present_user_friendly_fault,
ProvisioningTransport,
- select_profile_for_node,
SHORT_PRESENTATIONS,
)
from maasserver.testing.factory import factory
@@ -58,18 +30,11 @@
map_enum,
)
from metadataserver.models import NodeKey
-from provisioningserver.enum import (
- POWER_TYPE,
- PSERV_FAULT,
- )
-from provisioningserver.testing.factory import ProvisioningFakeFactory
-from testtools.deferredruntest import AsynchronousDeferredRunTest
+from provisioningserver.enum import PSERV_FAULT
from testtools.matchers import (
KeysEqual,
StartsWith,
)
-from testtools.testcase import ExpectedException
-from twisted.internet.defer import inlineCallbacks
import yaml
@@ -234,342 +199,6 @@
friendly_text)
-class ProvisioningTests:
- """Tests for the Provisioning API as maasserver sees it."""
-
- __metaclass__ = ABCMeta
-
- # This must be set to the provisioning server API proxy to test against.
- papi = None
-
- def make_node_without_saving(self, arch=ARCHITECTURE.i386):
- """Create a Node, but don't save it to the database."""
- system_id = factory.make_name("node")
- return Node(
- system_id=system_id, hostname=factory.getRandomString(),
- status=NODE_STATUS.DEFAULT_STATUS, after_commissioning_action=(
- NODE_AFTER_COMMISSIONING_ACTION.DEFAULT),
- architecture=arch)
-
- def test_name_arch_in_cobbler_style_converts_architecture_names(self):
- self.assertSequenceEqual(
- ['i386', 'i386', 'x86_64', 'x86_64'],
- map(
- name_arch_in_cobbler_style,
- ['i386', 'i686', 'amd64', 'x86_64']))
-
- def test_name_arch_in_cobbler_works_for_both_bytes_and_unicode(self):
- self.assertEqual(
- name_arch_in_cobbler_style(u'amd64'),
- name_arch_in_cobbler_style(b'amd64'))
-
- def test_name_arch_in_cobbler_returns_unicode(self):
- self.assertIsInstance(name_arch_in_cobbler_style(b'amd64'), unicode)
-
- def test_get_profile_name_selects_Precise_and_right_arch(self):
- architectures = map_enum(ARCHITECTURE).values()
- self.assertItemsEqual(
- [
- 'maas-precise-%s' % name_arch_in_cobbler_style(arch)
- for arch in architectures],
- [
- get_profile_name(arch)
- for arch in architectures])
-
- def test_get_profile_name_converts_architecture_name(self):
- profile = get_profile_name(architecture='amd64')
- self.assertNotIn('amd64', profile)
- self.assertIn('x86_64', profile)
-
- @inlineCallbacks
- def test_select_profile_for_node_ignores_previously_chosen_profile(self):
- node = factory.make_node(architecture='i386')
- profile = yield self.add_profile(self.papi)
- yield self.papi.modify_nodes({node.system_id: {'profile': profile}})
- self.assertEqual(
- 'maas-precise-i386', select_profile_for_node(node))
-
- def test_select_profile_for_node_works_for_commissioning(self):
- # A special profile is chosen for nodes in the commissioning
- # state.
- arch = ARCHITECTURE.i386
- node = factory.make_node(
- status=NODE_STATUS.COMMISSIONING, architecture=arch)
- profile = select_profile_for_node(node)
- self.assertEqual('maas-precise-%s-commissioning' % arch, profile)
-
- def test_provision_post_save_Node_create(self):
- # The handler for Node's post-save signal registers the node in
- # its current state with the provisioning server.
- node = factory.make_node(architecture=ARCHITECTURE.i386)
- provisioning.provision_post_save_Node(
- sender=Node, instance=node, created=True)
- system_id = node.system_id
- pserv_node = self.papi.get_nodes_by_name([system_id])[system_id]
- self.assertEqual("maas-precise-i386", pserv_node["profile"])
-
- def test_get_all_profile_names(self):
- expected_profiles = []
- for arch in map_enum(ARCHITECTURE).values():
- for commissioning in (False, True):
- expected_profiles.append(
- get_profile_name(arch, commissioning))
- self.assertItemsEqual(expected_profiles, get_all_profile_names())
-
- def test_provision_post_save_Node_returns_other_pserv_faults(self):
-
- def raise_fault(*args, **kwargs):
- raise Fault(PSERV_FAULT.NO_COBBLER, factory.getRandomString())
-
- self.patch(self.papi.proxy, 'add_node', raise_fault)
- with ExpectedException(ExternalComponentException):
- node = factory.make_node()
- provisioning.provision_post_save_Node(
- sender=Node, instance=node, created=True)
-
- def test_provision_post_save_Node_registers_effective_power_type(self):
- power_types = list(map_enum(POWER_TYPE).values())
- nodes = {
- power_type: factory.make_node(power_type=power_type)
- for power_type in power_types}
- effective_power_types = {
- power_type: node.get_effective_power_type()
- for power_type, node in nodes.items()}
- pserv_nodes = self.papi.get_nodes_by_name(
- node.system_id for node in nodes.values())
- pserv_power_types = {
- power_type: pserv_nodes[node.system_id]["power_type"]
- for power_type, node in nodes.items()}
- self.assertEqual(effective_power_types, pserv_power_types)
-
- def test_provision_post_save_MACAddress_create(self):
- # Creating and saving a MACAddress updates the Node with which it's
- # associated.
- node_model = factory.make_node(system_id="frank")
- node_model.add_mac_address("12:34:56:78:90:12")
- node = self.papi.get_nodes_by_name(["frank"])["frank"]
- self.assertEqual(["12:34:56:78:90:12"], node["mac_addresses"])
-
- def test_provision_post_save_Node_update(self):
- # Saving an existing node does not change the profile or distro
- # associated with it.
- node_model = factory.make_node(system_id="frank")
- provisioning.provision_post_save_Node(
- sender=Node, instance=node_model, created=True)
- # Record the current profile name.
- node = self.papi.get_nodes_by_name(["frank"])["frank"]
- profile_name1 = node["profile"]
- # Update the model node.
- provisioning.provision_post_save_Node(
- sender=Node, instance=node_model, created=False)
- # The profile name is unchanged.
- node = self.papi.get_nodes_by_name(["frank"])["frank"]
- profile_name2 = node["profile"]
- self.assertEqual(profile_name1, profile_name2)
-
- def test_provision_post_save_MACAddress_update(self):
- # Saving an existing MACAddress updates the Node with which it's
- # associated.
- node_model = factory.make_node(system_id="frank")
- mac_model = node_model.add_mac_address("12:34:56:78:90:12")
- mac_model.mac_address = "11:22:33:44:55:66"
- mac_model.save()
- node = self.papi.get_nodes_by_name(["frank"])["frank"]
- self.assertEqual(["11:22:33:44:55:66"], node["mac_addresses"])
-
- def test_provision_post_delete_Node(self):
- node_model = factory.make_node(system_id="frank")
- provisioning.provision_post_save_Node(
- sender=Node, instance=node_model, created=True)
- provisioning.provision_post_delete_Node(
- sender=Node, instance=node_model)
- # The node is deleted, but the profile and distro remain.
- self.assertNotEqual({}, self.papi.get_distros())
- self.assertNotEqual({}, self.papi.get_profiles())
- self.assertEqual({}, self.papi.get_nodes_by_name(["frank"]))
-
- def test_provision_post_delete_MACAddress(self):
- # Deleting a MACAddress updates the Node with which it's associated.
- node_model = factory.make_node(system_id="frank")
- node_model.add_mac_address("12:34:56:78:90:12")
- node_model.remove_mac_address("12:34:56:78:90:12")
- node = self.papi.get_nodes_by_name(["frank"])["frank"]
- self.assertEqual([], node["mac_addresses"])
-
- def test_papi_xmlrpc_faults_are_reported_helpfully(self):
-
- def raise_fault(*args, **kwargs):
- raise Fault(8002, factory.getRandomString())
-
- self.patch(self.papi.proxy, 'add_node', raise_fault)
-
- with ExpectedException(
- ExternalComponentException, ".*provisioning server.*"):
- self.papi.add_node('node', 'profile', 'power', '')
-
- def test_provisioning_errors_are_reported_helpfully(self):
-
- def raise_provisioning_error(*args, **kwargs):
- raise Fault(PSERV_FAULT.NO_COBBLER, factory.getRandomString())
-
- self.patch(self.papi.proxy, 'add_node', raise_provisioning_error)
-
- with ExpectedException(ExternalComponentException, ".*Cobbler.*"):
- self.papi.add_node('node', 'profile', 'power', '')
-
- def patch_and_call_papi_method(self, fault_code, papi_method='add_node'):
- # Patch papi method to make it raise a Fault of the provided
- # fault_code. Then call this method.
- def raise_provisioning_error(*args, **kwargs):
- raise Fault(fault_code, factory.getRandomString())
-
- self.patch(self.papi.proxy, papi_method, raise_provisioning_error)
-
- try:
- method = getattr(self.papi, papi_method)
- method()
- except MAASAPIException:
- pass
-
- def test_error_registered_when_NO_COBBLER_raised(self):
- self.patch(components, '_PERSISTENT_ERRORS', {})
- self.patch_and_call_papi_method(PSERV_FAULT.NO_COBBLER)
- errors = get_persistent_errors()
- self.assertEqual(1, len(errors))
- self.assertIn(
- "The provisioning server was unable to reach the Cobbler",
- errors[0])
-
- def test_error_registered_can_handle_all_the_exceptions(self):
- for fault_code in map_enum(PSERV_FAULT).values():
- self.patch(components, '_PERSISTENT_ERRORS', {})
- self.patch_and_call_papi_method(fault_code)
- errors = get_persistent_errors()
- self.assertEqual(1, len(errors))
-
- def patch_get_profiles_by_name(self, method):
- self.patch(components, '_PERSISTENT_ERRORS', {})
- self.patch(
- self.papi.proxy, 'get_profiles_by_name', method)
-
- def test_check_profiles_no_error_registered_if_all_profiles_found(self):
- def return_all_profiles(profiles):
- return profiles
- self.patch_get_profiles_by_name(return_all_profiles)
- check_profiles()
- self.assertEqual([], get_persistent_errors())
-
- def test_failing_components_cleared_if_add_node_works(self):
- self.patch(components, '_PERSISTENT_ERRORS', {})
- register_persistent_error(COMPONENT.PSERV, factory.getRandomString())
- register_persistent_error(COMPONENT.COBBLER, factory.getRandomString())
- register_persistent_error(
- COMPONENT.IMPORT_PXE_FILES, factory.getRandomString())
- self.papi.add_node('node', 'hostname', 'profile', 'power', '')
- self.assertEqual([], get_persistent_errors())
-
- def test_only_failing_components_are_cleared_if_modify_nodes_works(self):
- # Only the components listed in METHOD_COMPONENTS[method_name]
- # are cleared with the run of method_name is successfull.
- self.patch(components, '_PERSISTENT_ERRORS', {})
- other_error = factory.getRandomString()
- other_component = factory.getRandomString()
- register_persistent_error(other_component, other_error)
- self.papi.modify_nodes({})
- self.assertEqual([other_error], get_persistent_errors())
-
- def register_random_errors(self, failed_components):
- self.patch(components, '_PERSISTENT_ERRORS', {})
- for component in failed_components:
- register_persistent_error(component, factory.getRandomString())
-
- def test_failing_components_cleared_if_modify_nodes_works(self):
- self.register_random_errors((COMPONENT.PSERV, COMPONENT.COBBLER))
- self.papi.modify_nodes({})
- self.assertEqual([], get_persistent_errors())
-
- def test_failing_components_cleared_if_delete_nodes_by_name_works(self):
- self.register_random_errors((COMPONENT.PSERV, COMPONENT.COBBLER))
- other_error = factory.getRandomString()
- register_persistent_error(factory.getRandomString(), other_error)
- self.papi.delete_nodes_by_name([])
- self.assertEqual([other_error], get_persistent_errors())
-
- def test_failing_components_cleared_if_get_profiles_by_name_works(self):
- self.register_random_errors((COMPONENT.PSERV, COMPONENT.COBBLER))
- other_error = factory.getRandomString()
- register_persistent_error(factory.getRandomString(), other_error)
- self.papi.get_profiles_by_name([])
- self.assertEqual([other_error], get_persistent_errors())
-
-
-class TestProvisioningWithFake(ProvisioningTests, ProvisioningFakeFactory,
- TestCase):
- """Tests for the Provisioning API using a fake."""
-
- run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=5)
-
- def setUp(self):
- super(TestProvisioningWithFake, self).setUp()
- self.papi = provisioning.get_provisioning_api_proxy()
-
- def test_provision_post_save_Node_set_netboot_enabled(self):
- # When a node is under MAAS's control - i.e. not allocated and not
- # retired - it is always configured for netbooting. When the node is
- # allocated, netbooting is left alone; its state may change in
- # response to interactions between the node and the provisioning
- # server and MAAS ought to leave that alone. When the node is retired
- # netbooting is disabled.
- expected = {
- NODE_STATUS.DECLARED: False,
- NODE_STATUS.COMMISSIONING: True,
- NODE_STATUS.FAILED_TESTS: True,
- NODE_STATUS.MISSING: True,
- NODE_STATUS.READY: True,
- NODE_STATUS.RESERVED: True,
- NODE_STATUS.ALLOCATED: None, # No setting.
- NODE_STATUS.RETIRED: False,
- }
- nodes = {
- status: factory.make_node(status=status)
- for status, title in NODE_STATUS_CHOICES
- }
- pserv_nodes = {
- status: node.system_id
- for status, node in nodes.items()
- }
- observed = {
- status: self.papi.nodes[pserv_node].get("netboot_enabled")
- for status, pserv_node in pserv_nodes.items()
- }
- self.assertEqual(expected, observed)
-
- def test_commissioning_node_gets_commissioning_preseed(self):
- node = factory.make_node(status=NODE_STATUS.DECLARED)
- token = NodeKey.objects.get_token_for_node(node)
- node.start_commissioning(factory.make_admin())
- preseed = self.papi.nodes[node.system_id]['ks_meta']['MAAS_PRESEED']
- self.assertEqual(
- compose_commissioning_preseed(token), b64decode(preseed))
-
- def test_non_commissioning_node_gets_cloud_init_preseed(self):
- node = factory.make_node(status=NODE_STATUS.READY)
- token = NodeKey.objects.get_token_for_node(node)
- preseed = self.papi.nodes[node.system_id]['ks_meta']['MAAS_PRESEED']
- self.assertEqual(
- compose_cloud_init_preseed(token), b64decode(preseed))
-
- def test_node_gets_cloud_init_preseed_after_commissioning(self):
- node = factory.make_node(status=NODE_STATUS.DECLARED)
- token = NodeKey.objects.get_token_for_node(node)
- node.start_commissioning(factory.make_admin())
- node.status = NODE_STATUS.READY
- node.save()
- preseed = self.papi.nodes[node.system_id]['ks_meta']['MAAS_PRESEED']
- self.assertEqual(
- compose_cloud_init_preseed(token), b64decode(preseed))
-
-
class TestProvisioningTransport(TestCase):
"""Tests for :class:`ProvisioningTransport`."""
=== modified file 'src/metadataserver/tests/test_api.py'
--- src/metadataserver/tests/test_api.py 2012-08-03 14:28:46 +0000
+++ src/metadataserver/tests/test_api.py 2012-08-16 07:39:19 +0000
@@ -25,7 +25,6 @@
Unauthorized,
)
from maasserver.models import SSHKey
-from maasserver.provisioning import get_provisioning_api_proxy
from maasserver.testing import reload_object
from maasserver.testing.factory import factory
from maasserver.testing.oauthclient import OAuthAuthenticatedClient
@@ -371,21 +370,6 @@
self.assertEqual(httplib.OK, response.status_code)
self.assertEqual(NODE_STATUS.READY, reload_object(node).status)
- def test_signaling_commissioning_success_restores_node_profile(self):
- papi = get_provisioning_api_proxy()
- commissioning_profile = self.add_profile(papi)
- node = factory.make_node(status=NODE_STATUS.DECLARED)
- node_data = papi.get_nodes_by_name([node.system_id])[node.system_id]
- original_profile = node_data['profile']
- node.status = NODE_STATUS.COMMISSIONING
- node.save()
- papi.modify_nodes({node.system_id: {'profile': commissioning_profile}})
- client = self.make_node_client(node=node)
- response = self.call_signal(client, status='OK')
- self.assertEqual(httplib.OK, response.status_code)
- node_data = papi.get_nodes_by_name([node.system_id])[node.system_id]
- self.assertEqual(original_profile, node_data['profile'])
-
def test_signaling_commissioning_success_is_idempotent(self):
node = factory.make_node(status=NODE_STATUS.COMMISSIONING)
client = self.make_node_client(node=node)