From d7abd9e51a3618aa85c06e13f47a53924157af3a Mon Sep 17 00:00:00 2001
From: Mark Hamzy <hamzy@us.ibm.com>
Date: Sat, 11 Nov 2017 14:05:09 -0600
Subject: [PATCH] fix_multi_arch tripleo-common

---
 tripleo_common/actions/baremetal.py   | 35 +++++++-----------
 tripleo_common/actions/validations.py | 69 +++++++++++++++++++++++++----------
 tripleo_common/constants.py           |  4 --
 tripleo_common/utils/glance.py        | 29 ++++++++++++---
 tripleo_common/utils/nodes.py         | 53 ++++++++++++++++++++++-----
 workbooks/baremetal.yaml              | 18 ++-------
 workbooks/validations.yaml            | 58 +++++++++++++----------------
 7 files changed, 159 insertions(+), 107 deletions(-)

diff --git a/tripleo_common/actions/baremetal.py b/tripleo_common/actions/baremetal.py
index dc73355..3dd0f35 100644
--- a/tripleo_common/actions/baremetal.py
+++ b/tripleo_common/actions/baremetal.py
@@ -36,21 +36,18 @@ class RegisterOrUpdateNodes(base.TripleOAction):
 
     :param nodes_json: list of nodes & attributes in json format
     :param remove: Should nodes not in the list be removed?
-    :param kernel_name: Glance ID of the kernel to use for the nodes.
-    :param ramdisk_name: Glance ID of the ramdisk to use for the nodes.
     :param instance_boot_option: Whether to set instances for booting from
                                  local hard drive (local) or network (netboot).
     :return: list of node objects representing the new nodes.
     """
 
-    def __init__(self, nodes_json, remove=False, kernel_name=None,
-                 ramdisk_name=None, instance_boot_option='local'):
+    def __init__(self, nodes_json, remove=False, no_deploy_image=False,
+                 instance_boot_option='local'):
         super(RegisterOrUpdateNodes, self).__init__()
         self.nodes_json = nodes_json
         self.remove = remove
+        self.no_deploy_image = no_deploy_image
         self.instance_boot_option = instance_boot_option
-        self.kernel_name = kernel_name
-        self.ramdisk_name = ramdisk_name
 
     def run(self, context):
         for node in self.nodes_json:
@@ -67,9 +64,7 @@ class RegisterOrUpdateNodes(base.TripleOAction):
                 self.nodes_json,
                 client=baremetal_client,
                 remove=self.remove,
-                glance_client=image_client,
-                kernel_name=self.kernel_name,
-                ramdisk_name=self.ramdisk_name)
+                glance_client=image_client)
         except Exception as err:
             LOG.exception("Error registering nodes with ironic.")
             return actions.Result(error=six.text_type(err))
@@ -100,32 +95,30 @@ class ConfigureBootAction(base.TripleOAction):
     """Configure kernel and ramdisk.
 
     :param node_uuid: an Ironic node UUID
-    :param kernel_name: Glance name of the kernel to use for the nodes.
-    :param ramdisk_name: Glance name of the ramdisk to use for the nodes.
     :param instance_boot_option: Whether to set instances for booting from
                                  local hard drive (local) or network (netboot).
     """
 
-    def __init__(self, node_uuid, kernel_name='bm-deploy-kernel',
-                 ramdisk_name='bm-deploy-ramdisk', instance_boot_option=None):
+    def __init__(self, node_uuid, instance_boot_option=None):
         super(ConfigureBootAction, self).__init__()
         self.node_uuid = node_uuid
-        self.kernel_name = kernel_name
-        self.ramdisk_name = ramdisk_name
         self.instance_boot_option = instance_boot_option
 
     def run(self, context):
         baremetal_client = self.get_baremetal_client(context)
         image_client = self.get_image_client(context)
+        self.no_deploy_image = no_deploy_image
 
         try:
-            image_ids = {'kernel': None, 'ramdisk': None}
+            node = baremetal_client.node.get(self.node_uuid)
+
+            arch = node.properties.get('cpu_arch', 'x86_64')
+            arches[arch] = {'kernel': None, 'ramdisk': None}
+
             if self.kernel_name is not None and self.ramdisk_name is not None:
-                image_ids = glance.create_or_find_kernel_and_ramdisk(
+                arches = glance.create_or_find_kernel_and_ramdisk(
                     image_client, self.kernel_name, self.ramdisk_name)
 
-            node = baremetal_client.node.get(self.node_uuid)
-
             capabilities = node.properties.get('capabilities', {})
             capabilities = nodes.capabilities_to_dict(capabilities)
             if self.instance_boot_option is not None:
@@ -145,12 +138,12 @@ class ConfigureBootAction(base.TripleOAction):
                 {
                     'op': 'add',
                     'path': '/driver_info/deploy_ramdisk',
-                    'value': image_ids['ramdisk'],
+                    'value': arches[arch]['ramdisk'],
                 },
                 {
                     'op': 'add',
                     'path': '/driver_info/deploy_kernel',
-                    'value': image_ids['kernel'],
+                    'value': arches['arch']['kernel'],
                 },
             ])
             LOG.debug("Configuring boot option for Node %s", self.node_uuid)
diff --git a/tripleo_common/actions/validations.py b/tripleo_common/actions/validations.py
index 017f99d..18bfbe6 100644
--- a/tripleo_common/actions/validations.py
+++ b/tripleo_common/actions/validations.py
@@ -141,22 +141,25 @@ class CheckBootImagesAction(base.TripleOAction):
 
     # TODO(bcrochet): The validation actions are temporary. This logic should
     #                 move to the tripleo-validations project eventually.
-    def __init__(self, images,
-                 deploy_kernel_name=constants.DEFAULT_DEPLOY_KERNEL_NAME,
-                 deploy_ramdisk_name=constants.DEFAULT_DEPLOY_RAMDISK_NAME):
+    def __init__(self, nodes, images):
         super(CheckBootImagesAction, self).__init__()
+        self.nodes = nodes
         self.images = images
-        self.deploy_kernel_name = deploy_kernel_name
-        self.deploy_ramdisk_name = deploy_ramdisk_name
 
     def run(self, context):
         messages = []
-        kernel_id = self._check_for_image(self.deploy_kernel_name, messages)
-        ramdisk_id = self._check_for_image(self.deploy_ramdisk_name, messages)
+
+        arches = {}
+        for node in self.nodes:
+            properties = node['properties']
+            if 'cpu_arch' in properties:
+                arches[properties['cpu_arch']] = True
+
+        for arch in arches.keys():
+            self._check_for_image("%s-bm-deploy-kernel" % arch, messages)
+            self._check_for_image("%s-bm-deploy-ramdisk" % arch, messages)
 
         return_value = {
-            'kernel_id': kernel_id,
-            'ramdisk_id': ramdisk_id,
             'errors': messages,
             'warnings': []
         }
@@ -181,10 +184,6 @@ class CheckBootImagesAction(base.TripleOAction):
             messages.append(multiple_message.format(name))
         elif len(found_images) == 0:
             messages.append(missing_message.format(name))
-        else:
-            image_id = found_images[0]
-
-        return image_id
 
 
 class CheckFlavorsAction(base.TripleOAction):
@@ -265,31 +264,61 @@ class CheckNodeBootConfigurationAction(base.TripleOAction):
 
     # TODO(bcrochet): The validation actions are temporary. This logic should
     #                 move to the tripleo-validations project eventually.
-    def __init__(self, node, kernel_id, ramdisk_id):
+    def __init__(self, node, images):
         super(CheckNodeBootConfigurationAction, self).__init__()
 
         self.node = node
-        self.kernel_id = kernel_id
-        self.ramdisk_id = ramdisk_id
+        self.images = images
+
+    def _check_for_image(self, name):
+        found_images = [item['id'] for item in self.images
+                        if item['name'] == name]
+        if len(found_images) == 1:
+            return found_images[0]
+        else:
+            return None
 
     def run(self, context):
         warnings = []
         errors = []
+
+        cpu_arch = None
+        if self.node is None:
+            errors.append("self.node is None ")
+        elif 'properties' in self.node:
+            properties = self.node['properties']
+            if 'cpu_arch' in properties:
+                cpu_arch = properties['cpu_arch']
+            else:
+                errors.append("cpu_arch not in properties (%s) " % properties)
+        else:
+            errors.append("properties not in node (%s)" % self.node)
+
+        if cpu_arch is not None:
+            kernel_name = cpu_arch+'-bm-deploy-kernel'
+            ramdisk_name = cpu_arch+'-bm-deploy-ramdisk'
+            kernel_id = self._check_for_image(kernel_name)
+            ramdisk_id = self._check_for_image(ramdisk_name)
+            if kernel_id is None:
+                errors.append("%s is missing in image store" % kernel_name)
+            if ramdisk_id is None:
+                errors.append("%s is missing in image store" % ramdisk_name)
+
         message = ("Node {uuid} has an incorrectly configured "
                    "{property}. Expected \"{expected}\" but got "
                    "\"{actual}\".")
-        if self.node['driver_info'].get('deploy_ramdisk') != self.ramdisk_id:
+        if self.node['driver_info'].get('deploy_ramdisk') != ramdisk_id:
             errors.append(message.format(
                 uuid=self.node['uuid'],
                 property='driver_info/deploy_ramdisk',
-                expected=self.ramdisk_id,
+                expected=ramdisk_id,
                 actual=self.node['driver_info'].get('deploy_ramdisk')
             ))
-        if self.node['driver_info'].get('deploy_kernel') != self.kernel_id:
+        if self.node['driver_info'].get('deploy_kernel') != kernel_id:
             errors.append(message.format(
                 uuid=self.node['uuid'],
                 property='driver_info/deploy_kernel',
-                expected=self.kernel_id,
+                expected=kernel_id,
                 actual=self.node['driver_info'].get('deploy_kernel')
             ))
         capabilities = nodeutils.capabilities_to_dict(
diff --git a/tripleo_common/constants.py b/tripleo_common/constants.py
index a95f0d4..ad4d13b 100644
--- a/tripleo_common/constants.py
+++ b/tripleo_common/constants.py
@@ -131,10 +131,6 @@ PLAN_ENVIRONMENT = 'plan-environment.yaml'
 CONTAINER_DEFAULTS_ENVIRONMENT = ('environments/'
                                   'containers-default-parameters.yaml')
 
-DEFAULT_DEPLOY_KERNEL_NAME = 'bm-deploy-kernel'
-
-DEFAULT_DEPLOY_RAMDISK_NAME = 'bm-deploy-ramdisk'
-
 # The name for the swift container to host the cache for tripleo
 TRIPLEO_CACHE_CONTAINER = "__cache__"
 
diff --git a/tripleo_common/utils/glance.py b/tripleo_common/utils/glance.py
index b92409b..2fcf1a7 100644
--- a/tripleo_common/utils/glance.py
+++ b/tripleo_common/utils/glance.py
@@ -37,11 +37,30 @@ def create_or_find_kernel_and_ramdisk(glanceclient, kernel_name, ramdisk_name,
 
     :returns: A dictionary mapping kernel or ramdisk to the ID in Glance.
     """
-    kernel_image = _upload_file(glanceclient, kernel_name, kernel_path,
-                                'aki', 'Kernel', skip_missing=skip_missing)
-    ramdisk_image = _upload_file(glanceclient, ramdisk_name, ramdisk_path,
-                                 'ari', 'Ramdisk', skip_missing=skip_missing)
-    return {'kernel': kernel_image.id, 'ramdisk': ramdisk_image.id}
+
+
+    arches = {}
+    for node in baremetal_client.node.list(detail=True):
+        properties = node['properties']
+        if 'cpu_arch' in properties:
+            arches[properties['cpu_arch']] = {}
+
+    for arch in arches.keys():
+        kernel_name = "%s-bm-deploy-kernel" % arch
+        ramdisk_name = "%s-bm-deploy-ramdisk" % arch
+
+        kernel_image = _upload_file(glanceclient, kernel_name, kernel_path,
+                                    'aki', 'Kernel',
+                                    skip_missing=skip_missing)
+
+        ramdisk_image = _upload_file(glanceclient, ramdisk_name, ramdisk_path,
+                                     'ari', 'Ramdisk',
+                                     skip_missing=skip_missing)
+
+        arch['kernel'] = kernel_image.id
+        arch['ramdisk'] = ramdisk_image.id
+
+    return arches
 
 
 def _upload_file(glanceclient, name, path, disk_format, type_name,
diff --git a/tripleo_common/utils/nodes.py b/tripleo_common/utils/nodes.py
index d160a00..79eaf44 100644
--- a/tripleo_common/utils/nodes.py
+++ b/tripleo_common/utils/nodes.py
@@ -23,6 +23,9 @@ from oslo_concurrency import processutils
 from tripleo_common import exception
 from tripleo_common.utils import glance
 
+from glanceclient.v2.client import Client as real_glance_client
+from glanceclient import exc as exceptions
+
 LOG = logging.getLogger(__name__)
 
 _KNOWN_INTERFACE_FIELDS = [
@@ -449,8 +452,8 @@ def _clean_up_extra_nodes(seen, client, remove=False):
             LOG.debug('Extra registered node %s found.' % node)
 
 
-def register_all_nodes(nodes_list, client, remove=False, glance_client=None,
-                       kernel_name=None, ramdisk_name=None):
+def register_all_nodes(nodes_list, client, remove=False,
+                       no_deploy_image=False, glance_client=None):
     """Register all nodes in nodes_list in the baremetal service.
 
     :param nodes_list: The list of nodes to register.
@@ -465,17 +468,47 @@ def register_all_nodes(nodes_list, client, remove=False, glance_client=None,
     LOG.debug('Registering all nodes.')
     node_map = _populate_node_mapping(client)
 
-    glance_ids = {'kernel': None, 'ramdisk': None}
-    if kernel_name and ramdisk_name:
-        glance_ids = glance.create_or_find_kernel_and_ramdisk(
-            glance_client, kernel_name, ramdisk_name)
+    def find_image(glanceclient, name, disk_format):
+        image = None
+
+        if isinstance(glanceclient, real_glance_client):
+            images = glanceclient.images.list(name=name,
+                                              disk_format=disk_format)
+            for img in images:
+                if ((img['name'] == name or img['id'] == name) and
+                        img['disk_format'] == disk_format):
+                    image = img
+            if not image:
+                raise exceptions.NotFound("No image found")
+        else:
+            # TODO(dprince) remove this
+            # This code expects the python-openstackclient version of
+            # "glanceclient" (which isn't pure python-glanceclient) and is
+            # here for backwards compat until python-tripleoclient starts
+            # using the Mistral API for this functionality.
+            image = glanceclient.images.find(name=name,
+                                             disk_format=disk_format)
+
+        return image['id']
 
     seen = []
     for node in nodes_list:
-        if glance_ids['kernel'] and 'kernel_id' not in node:
-            node['kernel_id'] = glance_ids['kernel']
-        if glance_ids['ramdisk'] and 'ramdisk_id' not in node:
-            node['ramdisk_id'] = glance_ids['ramdisk']
+
+        kernel_id = find_image(glance_client,
+                               name=node['arch']+'-bm-deploy-kernel',
+                               disk_format='aki')
+        if not kernel_id:
+            raise exceptions.NotFound("No image found for "+kernel_name)
+
+        ramdisk_id = find_image(glance_client,
+                                name=node['arch']+'-bm-deploy-ramdisk',
+                                disk_format='ari')
+        if not ramdisk_id:
+            raise exceptions.NotFound("No image found for "+ramdisk_name)
+
+        if no_deploy_image == False:
+            node['kernel_id'] = kernel_id
+            node['ramdisk_id'] = ramdisk_id
 
         node = _update_or_register_ironic_node(node, node_map, client=client)
         seen.append(node)
diff --git a/workbooks/baremetal.yaml b/workbooks/baremetal.yaml
index 34b3f58..4de0351 100644
--- a/workbooks/baremetal.yaml
+++ b/workbooks/baremetal.yaml
@@ -147,9 +147,8 @@ workflows:
      - nodes_json
      - remove: False
      - queue_name: tripleo
-     - kernel_name: null
-     - ramdisk_name: null
      - instance_boot_option: local
+     - no_deploy_image
      - initial_state: manageable
 
     tags:
@@ -181,8 +180,7 @@ workflows:
         input:
            nodes_json: <% $.nodes_json %>
            remove: <% $.remove %>
-           kernel_name: <% $.kernel_name %>
-           ramdisk_name: <% $.ramdisk_name %>
+           no_deploy_image: <% $.no_deploy_image %>
            instance_boot_option: <% $.instance_boot_option %>
         publish:
           registered_nodes: <% task(register_or_update_nodes).result %>
@@ -700,8 +698,6 @@ workflows:
     input:
       - node_uuids
       - queue_name: tripleo
-      - kernel_name: bm-deploy-kernel
-      - ramdisk_name: bm-deploy-ramdisk
       - instance_boot_option: null
       - root_device: null
       - root_device_minimum_size: 4
@@ -716,7 +712,7 @@ workflows:
         on-success: configure_root_device
         on-error: set_status_failed_configure_boot
         with-items: node_uuid in <% $.node_uuids %>
-        action: tripleo.baremetal.configure_boot node_uuid=<% $.node_uuid %> kernel_name=<% $.kernel_name %> ramdisk_name=<% $.ramdisk_name %> instance_boot_option=<% $.instance_boot_option %>
+        action: tripleo.baremetal.configure_boot node_uuid=<% $.node_uuid %> instance_boot_option=<% $.instance_boot_option %>
 
       configure_root_device:
         on-success: send_message
@@ -759,8 +755,6 @@ workflows:
 
     input:
       - queue_name: tripleo
-      - kernel_name: 'bm-deploy-kernel'
-      - ramdisk_name: 'bm-deploy-ramdisk'
       - instance_boot_option: null
       - root_device: null
       - root_device_minimum_size: 4
@@ -785,8 +779,6 @@ workflows:
         input:
           node_uuids: <% $.managed_nodes %>
           queue_name: <% $.queue_name %>
-          kernel_name: <% $.kernel_name %>
-          ramdisk_name: <% $.ramdisk_name %>
           instance_boot_option: <% $.instance_boot_option %>
           root_device: <% $.root_device %>
           root_device_minimum_size: <% $.root_device_minimum_size %>
@@ -1174,8 +1166,6 @@ workflows:
       - ip_addresses
       - credentials
       - ports: [623]
-      - kernel_name: null
-      - ramdisk_name: null
       - instance_boot_option: local
       - initial_state: manageable
       - queue_name: tripleo
@@ -1207,8 +1197,6 @@ workflows:
         workflow: tripleo.baremetal.v1.register_or_update
         input:
           nodes_json: <% $.nodes_json %>
-          kernel_name: <% $.kernel_name %>
-          ramdisk_name: <% $.ramdisk_name %>
           instance_boot_option: <% $.instance_boot_option %>
           initial_state: <% $.initial_state %>
         on-success: send_message
diff --git a/workbooks/validations.yaml b/workbooks/validations.yaml
index 2ada12e..94d0f92 100644
--- a/workbooks/validations.yaml
+++ b/workbooks/validations.yaml
@@ -273,15 +273,11 @@ workflows:
 
   check_boot_images:
     input:
-      - deploy_kernel_name: 'bm-deploy-kernel'
-      - deploy_ramdisk_name: 'bm-deploy-ramdisk'
       - run_validations: true
       - queue_name: tripleo
     output:
       errors: <% $.errors %>
       warnings: <% $.warnings %>
-      kernel_id: <% $.kernel_id %>
-      ramdisk_id: <% $.ramdisk_id %>
     tags:
       - tripleo-common-managed
     tasks:
@@ -292,26 +288,37 @@ workflows:
 
       get_images:
         action: glance.images_list
-        on-success: check_images
+        on-success: get_ironic_nodes
         publish:
           images: <% task().result %>
 
+      get_ironic_nodes:
+        action: ironic.node_list
+        on-success: check_images
+        on-error: failed_get_ironic_nodes
+        input:
+          maintenance: false
+          detail: true
+        publish:
+          nodes: <% task().result %>
+
+      failed_get_ironic_nodes:
+        on-success: send_message
+        publish:
+          status: FAILED
+          message: <% task(get_ironic_nodes).result %>
+
       check_images:
         action: tripleo.validations.check_boot_images
         input:
+          nodes: <% $.nodes %>
           images: <% $.images %>
-          deploy_kernel_name: <% $.deploy_kernel_name %>
-          deploy_ramdisk_name: <% $.deploy_ramdisk_name %>
         on-success: send_message
         on-error: fail_check_images
         publish:
-          kernel_id: <% task().result.kernel_id %>
-          ramdisk_id: <% task().result.ramdisk_id %>
           warnings: <% task().result.warnings %>
           errors: <% task().result.errors %>
         publish-on-error:
-          kernel_id: <% task().result.kernel_id %>
-          ramdisk_id: <% task().result.ramdisk_id %>
           warnings: <% task().result.warnings %>
           errors: <% task().result.errors %>
 
@@ -333,8 +340,6 @@ workflows:
                 status: <% $.get('status', 'SUCCESS') %>
                 message: <% $.get('message', '') %>
                 execution: <% execution() %>
-                kernel_id: <% $.kernel_id %>
-                ramdisk_id: <% $.ramdisk_id %>
                 errors: <% $.errors %>
                 warnings: <% $.warnings %>
         on-success:
@@ -400,8 +405,6 @@ workflows:
 
   check_ironic_boot_configuration:
     input:
-      - kernel_id: null
-      - ramdisk_id: null
       - run_validations: true
       - queue_name: tripleo
     output:
@@ -419,7 +422,7 @@ workflows:
 
       get_ironic_nodes:
         action: ironic.node_list
-        on-success: check_node_boot_configuration
+        on-success: get_images
         on-error: failed_get_ironic_nodes
         input:
           provision_state: available
@@ -434,12 +437,17 @@ workflows:
           status: FAILED
           message: <% task(get_ironic_nodes).result %>
 
+      get_images:
+        action: glance.images_list
+        on-success: check_node_boot_configuration
+        publish:
+          images: <% task(get_images).result %>
+
       check_node_boot_configuration:
         action: tripleo.validations.check_node_boot_configuration
         input:
           node: <% $.node %>
-          kernel_id: <% $.kernel_id %>
-          ramdisk_id: <% $.ramdisk_id %>
+          images: <% $.images %>
         with-items: node in <% $.nodes %>
         on-success: send_message
         on-error: fail_check_node_boot_configuration
@@ -672,8 +680,6 @@ workflows:
 
   check_pre_deployment_validations:
     input:
-      - deploy_kernel_name: 'bm-deploy-kernel'
-      - deploy_ramdisk_name: 'bm-deploy-ramdisk'
       - roles_info: {}
       - stack_id: overcloud
       - parameters: {}
@@ -684,8 +690,6 @@ workflows:
     output:
       errors: <% $.errors %>
       warnings: <% $.warnings %>
-      kernel_id: <% $.kernel_id %>
-      ramdisk_id: <% $.ramdisk_id %>
       flavors: <% $.flavors %>
       statistics: <% $.statistics %>
     tags:
@@ -700,20 +704,14 @@ workflows:
       check_boot_images:
         workflow: check_boot_images
         input:
-          deploy_kernel_name: <% $.deploy_kernel_name %>
-          deploy_ramdisk_name: <% $.deploy_ramdisk_name %>
           run_validations: <% $.run_validations %>
           queue_name: <% $.queue_name %>
         publish:
           errors: <% $.errors + task().result.errors %>
           warnings: <% $.warnings + task().result.warnings %>
-          kernel_id: <% task().result.kernel_id %>
-          ramdisk_id: <% task().result.ramdisk_id %>
         publish-on-error:
           errors: <% $.errors + task().result.errors %>
           warnings: <% $.warnings + task().result.warnings %>
-          kernel_id: <% task().result.kernel_id %>
-          ramdisk_id: <% task().result.ramdisk_id %>
           status: FAILED
         on-success: collect_flavors
         on-error: collect_flavors
@@ -739,8 +737,6 @@ workflows:
       check_ironic_boot_configuration:
         workflow: check_ironic_boot_configuration
         input:
-          kernel_id: <% $.kernel_id %>
-          ramdisk_id: <% $.ramdisk_id %>
           run_validations: <% $.run_validations %>
           queue_name: <% $.queue_name %>
         publish:
@@ -801,8 +797,6 @@ workflows:
                 status: <% $.get('status', 'SUCCESS') %>
                 message: <% $.get('message', '') %>
                 execution: <% execution() %>
-                kernel_id: <% $.kernel_id %>
-                ramdisk_id: <% $.ramdisk_id %>
                 flavors: <% $.flavors %>
                 statistics: <% $.statistics %>
                 errors: <% $.errors %>
-- 
2.13.6

