From e396164faed7dc6674cb1f333a404cab064fbc6d Mon Sep 17 00:00:00 2001 From: Jay Faulkner Date: Fri, 10 Jun 2016 15:53:07 -0700 Subject: [PATCH 1/3] 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 From bbebea5a03b335f5370873e5e2b21338ad3c17c3 Mon Sep 17 00:00:00 2001 From: Jay Faulkner Date: Fri, 10 Jun 2016 16:32:11 -0700 Subject: [PATCH 2/3] Add README covering use cases for each example --- README.rst | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 README.rst diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..2cc23b4 --- /dev/null +++ b/README.rst @@ -0,0 +1,32 @@ +ipa-example-hardware-managers +============================= + +Example hardware managers for use with the `ironic python agent `_. + +Example Device Hardware Manager +------------------------------- + +This example manager is meant to demonstrate good patterns for developing a +device-specific hardware manager, such as for a specific version of NIC or +disk. + +Use Cases include: + * Adding device-specific clean-steps, such as to flash firmware or + verify it's still properly working after being provisioned. + * Implementing erase_device() using a vendor-provided utility for a given + disk model. + + +Example Business Logic Hardware Manager +--------------------------------------- + +This example manager is meant to demonstrate how cleaning and the agent can +use the node object and the node itself to enforce business logic and node +consistency. + +Use Cases include: + * Quality control on hardware by ensuring no component is beyond its useful + life. + * Asserting truths about the node; such as number of disks or total RAM. + * Reporting metrics about the node's hardware state. + * Overriding logic of get_os_install_device(). From ce9c5631e507fc23817d8c589666fb7487c65214 Mon Sep 17 00:00:00 2001 From: Jay Faulkner Date: Fri, 10 Jun 2016 16:58:47 -0700 Subject: [PATCH 3/3] Add basic information on using these examples --- README.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.rst b/README.rst index 2cc23b4..088b91a 100644 --- a/README.rst +++ b/README.rst @@ -3,6 +3,9 @@ ipa-example-hardware-managers Example hardware managers for use with the `ironic python agent `_. +Examples and Use Cases Provided +=============================== + Example Device Hardware Manager ------------------------------- @@ -30,3 +33,15 @@ Use Cases include: * Asserting truths about the node; such as number of disks or total RAM. * Reporting metrics about the node's hardware state. * Overriding logic of get_os_install_device(). + + +Make your own Manager based on these +==================================== +To make your own hardware manager based on these examples, copy or fork the +relevant examples out of this repository. Modify classnames and entrypoints +in setup.cfg to be not-examples. + +Since the entrypoints are defined in setup.cfg, simply installing your new +python package alongside IPA in a custom ramdisk should be enough to enable +the new hardware manager. +