.. _architecture: =================== System Architecture =================== High Level description ====================== An Ironic deployment will be composed of the following components: - An admin-only RESTful `API service`_, by which privileged users, such as cloud operators and other services within the cloud control plane, may interact with the managed bare metal servers. - A `Conductor service`_, which does the bulk of the work. Functionality is exposed via the `API service`_. The Conductor and API services communicate via RPC. - A Database and `DB API`_ for storing the state of the Conductor and Drivers. - A Deployment Ramdisk or Deployment Agent, which provide control over the hardware which is not available remotely to the Conductor. A ramdisk should be built which contains one of these agents, eg. with `diskimage-builder`_. This ramdisk can be booted on-demand. - **NOTE:** The agent is never run inside a tenant instance. Drivers ======= The internal driver API provides a consistent interface between the Conductor service and the driver implementations. A driver is defined by a class inheriting from the `BaseDriver`_ class, defining certain interfaces; each interface is an instance of the relevant driver module. For example, a fake driver class might look like this:: class FakePower(base.PowerInterface): def get_properties(self): return {} def validate(self, task): pass def get_power_state(self, task): return states.NOSTATE def set_power_state(self, task, power_state): pass def reboot(self, task): pass class FakeDriver(base.BaseDriver): def __init__(self): self.power = FakePower() There are three categories of driver interfaces: - `Core` interfaces provide the essential functionality for Ironic within OpenStack, and may be depended upon by other services. All drivers must implement these interfaces. The Core interfaces are `power` and `deploy`. - `Standard` interfaces provide functionality beyond the needs of OpenStack, but which have been standardized across all drivers and becomes part of Ironic's API. If a driver implements this interface, it must adhere to the standard. This is presented to encourage vendors to work together with the Ironic project and implement common features in a consistent way, thus reducing the burden on consumers of the API. The Standard interfaces are `management` and `console`. - The `Vendor` interface allows an exemption to the API contract when a vendor wishes to expose unique functionality provided by their hardware and is unable to do so within the `core` or `standard` interfaces. In this case, Ironic will merely relay the message from the API service to the appropriate driver. Driver-Specific Periodic Tasks ------------------------------ Drivers may run their own periodic tasks, i.e. actions run repeatedly after a certain amount of time. Such task is created by decorating a method on the driver itself or on any interface with driver_periodic_task_ decorator, e.g. :: class FakePower(base.PowerInterface): @base.driver_periodic_task(spacing=42) def task(self, manager, context): pass # do something class FakeDriver(base.BaseDriver): def __init__(self): self.power = FakePower() @base.driver_periodic_task(spacing=42) def task2(self, manager, context): pass # do something @base.driver_periodic_task(parallel=False) def blocking_task(self, manager, context): pass # do something fast, this blocks other tasks from starting! Here the ``spacing`` argument is a period in seconds for a given periodic task. For example 'spacing=5' means every 5 seconds. The ``parallel`` argument may be passed to driver_periodic_task_ and defaults to True. If False, this task will be run in the periodic task loop, rather than a separate greenthread. This should be used with caution, as it will cause all other periodic tasks to be blocked from starting while the non-parallel task is running. Long running tasks, especially any tasks that make a remote call (to a BMC, HTTP, etc.) **must** be parallelized. .. note:: By default periodic task names are derived from method names, so they should be unique within a Python module. Use ``name`` argument to driver_periodic_task_ to override automatically generated name. Message Routing =============== Each Conductor registers itself in the database upon start-up, and periodically updates the timestamp of its record. Contained within this registration is a list of the drivers which this Conductor instance supports. This allows all services to maintain a consistent view of which Conductors and which drivers are available at all times. Based on their respective driver, all nodes are mapped across the set of available Conductors using a `consistent hashing algorithm`_. Node-specific tasks are dispatched from the API tier to the appropriate conductor using conductor-specific RPC channels. As Conductor instances join or leave the cluster, nodes may be remapped to different Conductors, thus triggering various driver actions such as take-over or clean-up. .. _API service: ../webapi/v1.html .. _BaseDriver: ../api/ironic.drivers.base.html#ironic.drivers.base.BaseDriver .. _Conductor service: ../api/ironic.conductor.manager.html .. _DB API: ../api/ironic.db.api.html .. _diskimage-builder: https://github.com/openstack/diskimage-builder .. _consistent hashing algorithm: ../api/ironic.common.hash_ring.html .. _driver_periodic_task: ../api/ironic.drivers.base.html#ironic.drivers.base.driver_periodic_task