Merge pull request #1 from jayofdoom/jay/ExampleBusinessLogicManager
Add example business logic hardware manager
This commit is contained in:
commit
8fc36d5a6a
|
@ -0,0 +1,47 @@
|
||||||
|
ipa-example-hardware-managers
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Example hardware managers for use with the `ironic python agent <http://git.openstack.org/cgit/openstack/ironic-python-agent>`_.
|
||||||
|
|
||||||
|
Examples and Use Cases Provided
|
||||||
|
===============================
|
||||||
|
|
||||||
|
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().
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
|
@ -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)
|
|
@ -18,3 +18,4 @@ packages =
|
||||||
[entry_points]
|
[entry_points]
|
||||||
ironic_python_agent.hardware_managers =
|
ironic_python_agent.hardware_managers =
|
||||||
example_device = example_hardware_managers.example_device:ExampleDeviceHardwareManager
|
example_device = example_hardware_managers.example_device:ExampleDeviceHardwareManager
|
||||||
|
example_business_logic = example_hardware_managers.example_business_logic:ExampleBusinessLogicHardwareManager
|
||||||
|
|
Loading…
Reference in New Issue