Adding a New Provider Type¶
Introduction¶
Though not an exhaustive guide, this page details some of the tasks that need to be carried out in order for a new provider to be added and suported in the ManageIQ integration_tests framework.
wrapanapi¶
wrapanapi is a key component in the testing process. Each provider that we test has its own class within wrapanapi. The name of the project gives some indication as to what it does, it simply wraps-an-API. People ask why we use a wrapper around existing python library APIs. The answer is because we try to maintain a common API across the providers APIs where possible.
Validating information on the provider is important. When testing ManageIQ we don’t just rely on
the information it gives us, we need to ensure that the information is correct. To do that, we call
out to the provider itself and validate that if ManageIQ says there are 25 VMs, that there really
are 25VMs. Some simple methods are often present on the wrapanapi management class with names like
num_vm
. These simply return a count of the number of VMs that are present in the normal context.
You may often find that there are options to the method too. wrapanapi is designed to work primarily with ManageIQ for testing, but is also an Open Source system, allowing anyone to use it as a simple management tool for multiple provider types.
The first step in the process of adding a new provider is making a rudimentary wrapanapi class. This
should always be called ProviderSystem
, where Provider is a short name denoting your new provider.
Provider Type¶
If your provider doesn’t conform to the currently existing types, which broadly consist of Infrastructure and Cloud virtualization, Containers and Middleware, you will need a new provider type. You can think of this as a kind of super class that will be a reference point for all future classes of the same type. Though it is not entirely necessary. It is nice to create these to give others a springboard if they are creating a provider which is of the same type as yours.
The next part of the process is to create the provider type class within the integration_tests repository. This class will be used to represent your providers type in the ManageIQ system. It is your singular point of reference and will become your go to point of contact for all provider type related operations.
An example of a new provider type is below, we will take a moment to walk through the various parts of it.
The example above does a few things and we shall ignore the imports. Firstly we define the
PhysicalProvider class. Note that this follows the same format as in wrapanapi. Also note that this
class can’t really do anything. It is a placeholder that knows about things like, how to list
all the providers which are of type physical
.
The category
attribute is very important. It is used to classify your provider classes.
STATS_TO_MATCH
is a helper which is invoked during provider validation and will run the same
method on both the ManageIQ side, and the wrapanapi side, to ensure parity.
endpoints
, name
, key
are really the base level components to any provider. The endpoint
describes how to contact the provider, what its credentials are and its various methods of communication.
ManageIQ can sometimes interact with multiple endpoints on a provider. This allows that communication
to be represented inside the testing framework and to fill in the multiple endpoint forms in the UI.
The main credential is always called default
and endpoints takes the form of a dictionary which
is used to instantiate some Endpoint
objects. Please refer to existing providers for more
information on this.
Lastly there is a Navigation step defined. This is using the navmazing
component and should
be used as an example only. You should go and look up further examples of the navmazing
and
widgetastic
systems to understand how to interact with the UI. In this example, we are creating
reference to an All
destination which will, in the UI, navigate to a page showing all the
physical infrastructure providers.
Provider Class¶
Now that we have a provider type, or perhaps we already have one, we need to create a provider class. This class is a specific implementation of the provider. Anything which is not common across either the providers as a whole, or the even within the category of the provider, is recorded here.
from cfme.common.provider import DefaultEndpoint, DefaultEndpointForm
from . import PhysicalProvider
class BigBadEndpoint(DefaultEndpoint):
pass
class BigBadEndpointForm(DefaultEndpointForm):
pass
class BigBadProvider(PhysicalProvider):
type_name = 'bigbad'
endpoints_form = BigBadEndpointForm
string_name = "Ems Physical Infras"
mgmt_class = BigBadSystem # The reference to wrapanapi
def __init__(self, appliance, name=None, key=None, endpoints=None):
super(BigBadProvider, self).__init__(
appliance=appliance, name=name, key=key, endpoints=endpoints
)
@classmethod
def from_config(cls, prov_config, prov_key, appliance=None):
endpoint = BigBadEndpoint(**prov_config['endpoints']['default'])
return cls(name=prov_config['name'],
endpoints={endpoint.name: endpoint},
key=prov_key,
appliance=appliance)
@property
def view_value_mapping(self):
return {'name': self.name,
'prov_type': 'BigBad Provider'
}
To note are the endpoints. You can see here that we are inheriting some default forms. These are
used for almost every provider. They provide support for simple username/password combinations.
In the from_config
method, we have provider specific instantiation of the class. You can
see that we instantiate the BigBadEndpoint
class by passing it information from the
prov_config
. This is the data which is stored in the yamls and looks similar to the following.
big-bad-prov:
name: bigbad
type: bigbad
tags:
- default
endpoints:
default:
ipaddress: xx.xx.xx.xx
hostname: bigbadprovider.something.com
credentials: mycreds
The last point of note in this example is the view_value_mapping
property. This is responsible
for returning specific form data what is not covered by endpoints. In ManageIQ, there is a need to
select the provider type when adding a new provider and this providers that type.
Registering your Provider¶
Before your provider can be used in any tests it first must be registered. This is achieved by adding it to setup.py. You should be familiar with the entrypoints system to do this. Below you can see the examples of how the provider is added for the previous types.
entry_points={
'manageiq.provider_categories':
[
'infra = cfme.infrastructure.provider:InfraProvider',
'cloud = cfme.cloud.provider:CloudProvider',
'middleware = cfme.middleware.provider:MiddlewareProvider',
'containers = cfme.containers.provider:ContainersProvider',
'physical = cfme.physical.provider:PhysicalProvider',
],
'manageiq.provider_types.infra': [
'virtualcenter = cfme.infrastructure.provider.virtualcenter:VMwareProvider',
'scvmm = cfme.infrastructure.provider.scvmm:SCVMMProvider',
'rhevm = cfme.infrastructure.provider.rhevm:RHEVMProvider',
'openstack_infra = cfme.infrastructure.provider.openstack_infra:OpenstackInfraProvider',
],
'manageiq.provider_types.cloud': [
'ec2 = cfme.cloud.provider.ec2:EC2Provider',
'openstack = cfme.cloud.provider.openstack:OpenStackProvider',
'azure = cfme.cloud.provider.azure:AzureProvider',
'gce = cfme.cloud.provider.gce:GCEProvider',
],
'manageiq.provider_types.middleware': [
'hawkular = cfme.middleware.provider.hawkular:HawkularProvider',
],
'manageiq.provider_types.containers': [
'openshift = cfme.containers.provider.openshift:OpenshiftProvider',
],
'manageiq.provider_types.physical': [
'hawkular = cfme.middleware.provider.bigbad:BigBadProvider',
],
}