From e396164faed7dc6674cb1f333a404cab064fbc6d Mon Sep 17 00:00:00 2001 From: Jay Faulkner Date: Fri, 10 Jun 2016 15:53:07 -0700 Subject: [PATCH] Add example business logic hardware manager This adds an example hardware manager that would be useful for enforcing organizational policies, forcing machines to CLEANFAIL that are out of spec. --- .../example_business_logic.py | 97 +++++++++++++++++++ setup.cfg | 1 + 2 files changed, 98 insertions(+) create mode 100644 example_hardware_managers/example_business_logic.py diff --git a/example_hardware_managers/example_business_logic.py b/example_hardware_managers/example_business_logic.py new file mode 100644 index 0000000..0006b04 --- /dev/null +++ b/example_hardware_managers/example_business_logic.py @@ -0,0 +1,97 @@ +# Copyright 2015 Rackspace, 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. + +import time + +from ironic_python_agent import errors +from ironic_python_agent import hardware +from oslo_log import log + +LOG = log.getLogger() + + +class ExampleBusinessLogicHardwareManager(hardware.HardwareManager): + """Example hardware manager to enforce business logic""" + + # All hardware managers have a name and a version. + # Version should be bumped anytime a change is introduced. This will + # signal to Ironic that if automatic node cleaning is in progress to + # restart it from the beginning, to ensure consistency. The value can + # be anything; it's checked for equality against previously seen + # name:manager pairs. + HARDWARE_MANAGER_NAME = 'ExampleBusinessLogicHardwareManager' + HARDWARE_MANAGER_VERSION = '1' + + def evaluate_hardware_support(self): + """Declare level of hardware support provided. + + Since this example is explicitly about enforcing business logic during + cleaning, we want to return a static value. + + :returns: HardwareSupport level for this manager. + """ + return hardware.HardwareSupport.SERVICE_PROVIDER + + def get_clean_steps(self, node, ports): + """Get a list of clean steps with priority. + + Define any clean steps added by this manager here. These will be mixed + with other loaded managers that support this hardware, and ordered by + priority. Higher priority steps run earlier. + + Note that out-of-band clean steps may also be provided by Ironic. + These will follow the same priority ordering even though they are not + executed by IPA. + + There is *no guarantee whatsoever* that steps defined here will be + executed by this HardwareManager. When it comes time to run these + steps, they'll be called using dispatch_to_managers() just like any + other IPA HardwareManager method. This means if they are unique to + your hardware, they should be uniquely named. For example, + upgrade_firmware would be a bad step name. Whereas + upgrade_foobar_device_firmware would be better. + + :param node: The node object as provided by Ironic. + :param ports: Port objects as provided by Ironic. + :returns: A list of cleaning steps, as a list of dicts. + """ + # While obviously you could actively run code here, generally this + # should just return a static value, as any initialization and + # detection should've been done in evaluate_hardware_support(). + return [{ + 'step': 'companyx_verify_device_lifecycle', + 'priority': 472, + # If you need Ironic to coordinate a reboot after this step + # runs, but before continuing cleaning, this should be true. + 'reboot_requested': False, + # If it's safe for Ironic to abort cleaning while this step + # runs, this should be true. + 'abortable': True + }] + + # Other examples of interesting cleaning steps for this kind of hardware + # manager would include verifying node.properties matches current state of + # the node, checking smart stats to ensure the disk is not soon to fail, + # or enforcing security policies. + def companyx_verify_device_lifecycle(self, node, ports): + """Verify node is not beyond useful life of 3 years.""" + create_date = node.get('created_at') + if create_date is not None: + server_age = time.time() - time.mktime(time.strptime(create_date)) + if server_age > (60 * 60 * 24 * 365 * 3): + raise errors.CleaningError( + 'Server is too old to pass cleaning!') + else: + LOG.info('Node is %s seconds old, younger than 3 years, ' + 'cleaning passes.', server_age) diff --git a/setup.cfg b/setup.cfg index b350b91..ff0cfc0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -18,3 +18,4 @@ packages = [entry_points] ironic_python_agent.hardware_managers = example_device = example_hardware_managers.example_device:ExampleDeviceHardwareManager + example_business_logic = example_hardware_managers.example_business_logic:ExampleBusinessLogicHardwareManager