Add validation for checking node counts
This validation checks that available nodes is sufficient for what is requested. Change-Id: I1f3266275c39e093ddae18f93185eff3e4f74675 Implements: blueprint workflow-move-validations Closes-Bug: #1632704
This commit is contained in:
parent
af792d02e5
commit
9cf1f893d6
|
@ -16,12 +16,13 @@
|
|||
# under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
from six import string_types
|
||||
|
||||
import collections
|
||||
|
||||
from keystoneauth1.identity import generic as ks_id
|
||||
from keystoneauth1 import session
|
||||
from six import string_types
|
||||
from novaclient import client as nova_client
|
||||
from swiftclient.client import Connection
|
||||
|
||||
|
||||
|
@ -50,6 +51,17 @@ def get_swift_client(preauthurl, preauthtoken):
|
|||
max_backoff=120)
|
||||
|
||||
|
||||
def get_nova_client(auth_variables):
|
||||
auth_url = auth_variables.get('auth_url')
|
||||
username = auth_variables.get('username')
|
||||
project_name = auth_variables.get('project_name')
|
||||
token = auth_variables.get('os_auth_token')
|
||||
session = get_auth_session(auth_url, username, project_name,
|
||||
auth_token=token)
|
||||
|
||||
return nova_client.Client(2, session=session)
|
||||
|
||||
|
||||
def filtered(obj):
|
||||
"""Only return properties of obj whose value can be properly serialized."""
|
||||
return {k: v for k, v in obj.__dict__.items()
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
- hosts: undercloud
|
||||
vars:
|
||||
metadata:
|
||||
name: Verify hypervisor statistics
|
||||
description: >
|
||||
This validation checks that the nodes and hypervisor statistics
|
||||
add up.
|
||||
groups:
|
||||
- pre-deployment
|
||||
tasks:
|
||||
- name: Retrieve the hypervisor statistics
|
||||
set_fact:
|
||||
statistics: "{{ lookup('nova_hypervisor_statistics', wantlist=True) }}"
|
||||
|
||||
- name: Get default role counts
|
||||
set_fact:
|
||||
roles_info: "{{ lookup('roles_info', wantlist=True) }}"
|
||||
|
||||
- name: Set requested count
|
||||
set_fact:
|
||||
requested_count: "{{ roles_info|sum(attribute='count') }}"
|
||||
|
||||
- name: Get associated nodes
|
||||
set_fact:
|
||||
associated_nodes: "{{ lookup('ironic_nodes', 'associated', wantlist=True) }}"
|
||||
|
||||
- name: Get available nodes
|
||||
set_fact:
|
||||
available_nodes: "{{ lookup('ironic_nodes', 'provision_state', ['available'], wantlist=True) }}"
|
||||
|
||||
- name: Set count of available nodes
|
||||
set_fact:
|
||||
available_count: "{{ ((associated_nodes|length) + (available_nodes|length))|int }}"
|
||||
|
||||
- name: Fail when requested is more than available
|
||||
fail:
|
||||
msg: >
|
||||
Not enough baremetal nodes - available: {{ available_count }},
|
||||
requested: {{ requested_count }}
|
||||
failed_when: requested_count|int > available_count|int
|
||||
|
||||
- name: Fail when hypervisor count is less than available count
|
||||
fail:
|
||||
msg: >
|
||||
Only {{ statistics.count }} nodes are exposed to Nova of
|
||||
{{ available_count }} requests. Check that enough nodes are
|
||||
in 'available' state with maintenance mode off.
|
||||
failed_when: statistics.count < available_count|int
|
||||
|
|
@ -42,10 +42,22 @@ EXAMPLES = """
|
|||
- name: Get all nodes for a set of instance UUIDs
|
||||
debug:
|
||||
msg: |
|
||||
{{ lookup(''ironic_nodes', 'instance_uuid',
|
||||
{{ lookup('ironic_nodes', 'instance_uuid',
|
||||
['1691a1c7-9974-4bcc-a07a-5dec7fc04da0',
|
||||
'07f2435d-820c-46ce-9097-cf8a7282293e'],
|
||||
wantlist=True) }}"
|
||||
|
||||
- name: Get all nodes marked as 'associated'
|
||||
debug:
|
||||
msg: |
|
||||
{{ lookup('ironic_nodes', 'associated',
|
||||
wantlist=True) }}"
|
||||
|
||||
- name: Get nodes in provision state, and not associated or in maintenance
|
||||
debug:
|
||||
msg: |
|
||||
{{ lookup('ironic_nodes', 'provision_state',
|
||||
['available', 'inspect'], wantlist=True)}}
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
|
@ -82,6 +94,18 @@ class LookupModule(LookupBase):
|
|||
nodes = [ironic.node.get_by_instance_uuid(uuid)
|
||||
for uuid in terms[1]]
|
||||
return [utils.filtered(node) for node in nodes]
|
||||
elif terms[0] == 'associated':
|
||||
nodes = ironic.node.list(associated=True, detail=True)
|
||||
return [utils.filtered(node) for node in nodes]
|
||||
elif terms[0] == 'provision_state':
|
||||
nodes = []
|
||||
for term in terms[1]:
|
||||
nodes.extend(ironic.node.list(
|
||||
provision_state=term,
|
||||
associated=False,
|
||||
maintenance=False,
|
||||
detail=True))
|
||||
return [utils.filtered(node) for node in nodes]
|
||||
else:
|
||||
return [utils.filtered(node)
|
||||
for node in ironic.node.list(detail=True)]
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2018 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
from tripleo_validations import utils
|
||||
|
||||
|
||||
DOCUMENTATION = """
|
||||
lookup: nova_hypervisor_statistics
|
||||
description: Retrieve hypervisor statistic information from Nova
|
||||
long_description:
|
||||
- Load hypervisor statistics using the Nova API.
|
||||
author: Brad P. Crochet <brad@redhat.com>
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Get all hypervisor statistics from nova
|
||||
debug:
|
||||
msg: |
|
||||
{{ lookup('nova_hypervisor_statistics') }}
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
_raw:
|
||||
description: A Python list with results from the API call.
|
||||
"""
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
"""Returns server information from nova."""
|
||||
nova = utils.get_nova_client(variables)
|
||||
|
||||
statistics = nova.hypervisor_stats.statistics()
|
||||
|
||||
return utils.filtered(statistics)
|
Loading…
Reference in New Issue