diff --git a/bifrost/inventory.py b/bifrost/inventory.py index 55d646ad5..f4505eddf 100755 --- a/bifrost/inventory.py +++ b/bifrost/inventory.py @@ -25,10 +25,10 @@ from oslo_log import log import yaml try: - import shade - SHADE_LOADED = True + import openstack + SDK_LOADED = True except ImportError: - SHADE_LOADED = False + SDK_LOADED = False DOCUMENTATION = ''' Bifrost Inventory Module @@ -323,34 +323,16 @@ def _process_baremetal_csv(data_source, groups, hostvars): return (groups, hostvars) -def _identify_shade_auth(): - """Return shade credentials""" - if os.environ.get('OS_CLOUD'): - return {} - endpoint = os.getenv( - 'OS_ENDPOINT', - os.getenv( - 'OS_URL', os.getenv('IRONIC_URL', "http://localhost:6385/"))) - options = dict( - auth_type="None", - auth=dict(endpoint=endpoint,) - ) - if os.environ.get('OS_AUTH_URL'): - options['auth_type'] = "password" - options['auth'] = dict( - username=os.getenv('OS_USERNAME', ""), - password=os.getenv('OS_PASSWORD', ""), - auth_url=os.getenv('OS_AUTH_URL', ""), - project_name=os.getenv('OS_PROJECT_NAME', ""), - domain_id=os.getenv('OS_USER_DOMAIN_NAME', ""), - ) - return options +def _process_sdk(groups, hostvars): + """Retrieve inventory utilizing OpenStackSDK.""" + # NOTE(dtantsur): backward compatibility + if os.environ.get('IRONIC_URL'): + print("WARNING: IRONIC_URL is deprecated, use OS_ENDPOINT") + os.environ['OS_ENDPOINT'] = os.environ['IRONIC_URL'] + if os.environ.get('OS_ENDPOINT') and not os.environ.get('OS_AUTH_URL'): + os.environ['OS_AUTH_TYPE'] = None - -def _process_shade(groups, hostvars): - """Retrieve inventory utilizing Shade""" - options = _identify_shade_auth() - cloud = shade.operator_cloud(**options) + cloud = openstack.connect() machines = cloud.list_machines() node_names = os.environ.get('BIFROST_NODE_NAMES', None) @@ -432,12 +414,12 @@ def main(): "Tried JSON, YAML, and CSV formats") sys.exit(1) elif "ironic" in data_source: - if SHADE_LOADED: - (groups, hostvars) = _process_shade(groups, hostvars) + if SDK_LOADED: + (groups, hostvars) = _process_sdk(groups, hostvars) else: LOG.error("BIFROST_INVENTORY_SOURCE is set to ironic " - "however the shade library failed to load, and may " - "not be present.") + "however the openstacksdk library failed to load, " + "and may not be present.") sys.exit(1) else: LOG.error('BIFROST_INVENTORY_SOURCE does not define a file') diff --git a/bifrost/tests/unit/test_inventory.py b/bifrost/tests/unit/test_inventory.py index 64db5175a..c797aaeba 100644 --- a/bifrost/tests/unit/test_inventory.py +++ b/bifrost/tests/unit/test_inventory.py @@ -21,6 +21,8 @@ Tests for `inventory` module. from unittest import mock +import openstack + from bifrost import inventory from bifrost.tests import base @@ -42,11 +44,10 @@ class TestBifrostInventoryUnit(base.TestCase): self.assertEqual('yes', inventory._val_or_none(array, 2)) self.assertIsNone(inventory._val_or_none(array, 4)) - def test__process_shade(self): - inventory.shade = mock_shade = mock.Mock() - inventory.SHADE_LOADED = True + @mock.patch.object(openstack, 'connect', autospec=True) + def test__process_sdk(self, mock_sdk): (groups, hostvars) = inventory._prepare_inventory() - mock_cloud = mock_shade.operator_cloud.return_value + mock_cloud = mock_sdk.return_value mock_cloud.list_machines.return_value = [ { 'driver_info': { @@ -67,9 +68,7 @@ class TestBifrostInventoryUnit(base.TestCase): 'uuid': 'e2be93b5-a8f6-46a2-bec7-571b8ecf2938', }, ] - (groups, hostvars) = inventory._process_shade(groups, hostvars) - mock_shade.operator_cloud.assert_called_once_with( - auth_type='None', auth={'endpoint': 'http://localhost:6385/'}) + (groups, hostvars) = inventory._process_sdk(groups, hostvars) mock_cloud.list_machines.assert_called_once_with() mock_cloud.list_nics_for_machine.assert_called_once_with( 'f3fbf7c6-b4e9-4dd2-8ca0-c74a50f8be45') @@ -95,11 +94,10 @@ class TestBifrostInventoryUnit(base.TestCase): } self.assertEqual(hostvars['node1'], expected_machine) - def test__process_shade_multiple_nics(self): - inventory.shade = mock_shade = mock.Mock() - inventory.SHADE_LOADED = True + @mock.patch.object(openstack, 'connect', autospec=True) + def test__process_sdk_multiple_nics(self, mock_sdk): (groups, hostvars) = inventory._prepare_inventory() - mock_cloud = mock_shade.operator_cloud.return_value + mock_cloud = mock_sdk.return_value mock_cloud.list_machines.return_value = [ { 'driver_info': { @@ -124,9 +122,7 @@ class TestBifrostInventoryUnit(base.TestCase): 'uuid': '59e8cd37-4f71-4ca1-a264-93c2ca7de0f7', }, ] - (groups, hostvars) = inventory._process_shade(groups, hostvars) - mock_shade.operator_cloud.assert_called_once_with( - auth_type='None', auth={'endpoint': 'http://localhost:6385/'}) + (groups, hostvars) = inventory._process_sdk(groups, hostvars) mock_cloud.list_machines.assert_called_once_with() mock_cloud.list_nics_for_machine.assert_called_once_with( 'f3fbf7c6-b4e9-4dd2-8ca0-c74a50f8be45') diff --git a/doc/source/install/offline-install.rst b/doc/source/install/offline-install.rst index f5dc44ae0..0d53ac9fa 100644 --- a/doc/source/install/offline-install.rst +++ b/doc/source/install/offline-install.rst @@ -48,7 +48,6 @@ this. cirros_deploy_image_upstream_url: file:///vagrant/cirros-0.4.0-x86_64-disk.img dib_git_url: file:///vagrant/git/diskimage-builder ironicclient_git_url: file:///vagrant/git/python-ironicclient - shade_git_url: file:///vagrant/git/shade ironic_git_url: file:///vagrant/git/ironic If this list becomes out of date, it's simple enough to find the things that diff --git a/doc/source/user/howto.rst b/doc/source/user/howto.rst index 32650893b..7b6d10523 100644 --- a/doc/source/user/howto.rst +++ b/doc/source/user/howto.rst @@ -46,12 +46,9 @@ registered in Ironic. Enroll Hardware =============== -The following requirements are installed during the install process +The openstacksdk library is installed during the install process as documented in the install documentation. -- openstack/shade library -- openstack/os-client-config - In order to enroll hardware, you will naturally need an inventory of your hardware. When utilizing the dynamic inventory module and accompanying roles the inventory can be supplied in one of three ways, diff --git a/lower-constraints.txt b/lower-constraints.txt index 20610a2ed..a4a8102ee 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -24,6 +24,7 @@ mox3==0.25.0 msgpack==0.5.6 netaddr==0.7.19 netifaces==0.10.6 +openstacksdk==0.37.0 os-client-config==1.29.0 oslo.config==5.2.0 oslo.context==2.20.0 diff --git a/playbooks/example-deploy-all-available-nodes.yaml b/playbooks/example-deploy-all-available-nodes.yaml index 249c63a64..9d096f2d1 100644 --- a/playbooks/example-deploy-all-available-nodes.yaml +++ b/playbooks/example-deploy-all-available-nodes.yaml @@ -11,10 +11,10 @@ # other operating systems or if your target node has multiple ethernet # interfaces. # -# NOTE(TheJulia): A user could utilize the os_ironic_facts module with another -# data source such as a CSV, YAML, or JSON file formats to query ironic, and -# the example role conditionals below to query current status and deploy to -# nodes. +# NOTE(TheJulia): A user could utilize the os_ironic_node_info module with +# another data source such as a CSV, YAML, or JSON file formats to query +# ironic, and the example role conditionals below to query current status and +# deploy to nodes. --- - hosts: localhost connection: local diff --git a/playbooks/library/os_ironic_facts.py b/playbooks/library/os_ironic_facts.py deleted file mode 100644 index aeca3454b..000000000 --- a/playbooks/library/os_ironic_facts.py +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 -*- - -# (c) 2015, Hewlett-Packard Development Company, L.P. -# -# This module is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This software is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this software. If not, see . - -try: - import shade - HAS_SHADE = True -except ImportError: - HAS_SHADE = False - -DOCUMENTATION = ''' ---- -module: os_ironic_facts -short_description: Searches Ironic and returns node facts. -extends_documentation_fragment: openstack -description: - - Queries Ironic for a requested node and returns facts about - the node, or fails if the node is not found. This module actively - prevents any passwords in the node driver_info from being returned. -options: - mac: - description: - - unique mac address that is used to attempt to identify the host. - required: false - default: None - uuid: - description: - - globally unique identifier (UUID) to identify the host. - required: false - default: None - name: - description: - - unique name identifier to identify the host in Ironic. - required: false - default: None - ironic_url: - description: - - If noauth mode is utilized, this is required to be set to the - endpoint URL for the Ironic API. Use with "auth" and "auth_type" - settings set to None. - required: false - default: None - -requirements: ["shade", "six"] -''' - -EXAMPLES = ''' -# Enroll a node with some basic properties and driver info -- os_ironic_facts: - name: "testvm1" -''' - - -def _choose_id_value(module): - if module.params['uuid']: - return module.params['uuid'] - if module.params['name']: - return module.params['name'] - return None - - -def main(): - argument_spec = openstack_full_argument_spec( # noqa: F405 - auth_type=dict(required=False), - uuid=dict(required=False), - name=dict(required=False), - mac=dict(required=False), - ironic_url=dict(required=False), - skip_items=dict(required=False, type='list'), - ) - module_kwargs = openstack_module_kwargs() # noqa: F405 - module = AnsibleModule(argument_spec, **module_kwargs) # noqa: F405 - - if not HAS_SHADE: - module.fail_json(msg='shade is required for this module') - if (module.params['auth_type'] in [None, 'None'] and - module.params['ironic_url'] is None): - module.fail_json(msg="Authentication appears to be disabled, " - "Please define an ironic_url parameter") - - if (module.params['ironic_url'] and - module.params['auth_type'] in [None, 'None']): - module.params['auth'] = dict( - endpoint=module.params['ironic_url'] - ) - - try: - cloud = shade.operator_cloud(**module.params) - - if module.params['name'] or module.params['uuid']: - server = cloud.get_machine(_choose_id_value(module)) - elif module.params['mac']: - server = cloud.get_machine_by_mac(module.params['mac']) - else: - module.fail_json(msg="The worlds did not align, " - "the host was not found as " - "no name, uuid, or mac was " - "defined.") - if server: - facts = dict(server) - new_driver_info = dict() - # Rebuild driver_info to remove any password values - # as they will be masked. - for key, value in facts['driver_info'].items(): - if 'password' not in key: - new_driver_info[key] = value - if new_driver_info: - facts['driver_info'] = new_driver_info - - for item in module.params['skip_items']: - if item in facts: - del facts[item] - - # Remove ports and links as they are useless in the ansible - # use context. - if "ports" in facts: - del facts["ports"] - if "links" in facts: - del facts["links"] - - module.exit_json(changed=False, ansible_facts=facts) - - else: - module.fail_json(msg="node not found.") - - except shade.OpenStackCloudException as e: - module.fail_json(msg=e.message) - - -# this is magic, see lib/ansible/module_common.py -from ansible.module_utils.basic import * # noqa: E402 -from ansible.module_utils.openstack import * # noqa: E402 -main() diff --git a/playbooks/library/os_ironic_facts.py b/playbooks/library/os_ironic_facts.py new file mode 120000 index 000000000..8b0db8cfd --- /dev/null +++ b/playbooks/library/os_ironic_facts.py @@ -0,0 +1 @@ +os_ironic_node_info.py \ No newline at end of file diff --git a/playbooks/library/os_ironic_node_info.py b/playbooks/library/os_ironic_node_info.py new file mode 100644 index 000000000..d73c1ae55 --- /dev/null +++ b/playbooks/library/os_ironic_node_info.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python +# coding: utf-8 -*- + +# (c) 2015, Hewlett-Packard Development Company, L.P. +# +# This module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software. If not, see . + +try: + import openstack + HAS_SDK = True +except ImportError: + HAS_SDK = False + +DOCUMENTATION = ''' +--- +module: os_ironic_node_info +short_description: Searches Ironic and returns node information. +extends_documentation_fragment: openstack +description: + - Queries Ironic for a requested node and returns "node" variable with + information about the node, or fails if the node is not found. This + module actively prevents any passwords in the node driver_info from being + returned. +options: + mac: + description: + - unique mac address that is used to attempt to identify the host. + required: false + default: None + uuid: + description: + - globally unique identifier (UUID) to identify the host. + required: false + default: None + name: + description: + - unique name identifier to identify the host in Ironic. + required: false + default: None + ironic_url: + description: + - If noauth mode is utilized, this is required to be set to the + endpoint URL for the Ironic API. Use with "auth" and "auth_type" + settings set to None. + required: false + default: None + +requirements: ["openstacksdk"] +''' + +EXAMPLES = ''' +# Get information about the node called "testvm1" and store in "node_info.node" +- os_ironic_node_info: + name: "testvm1" + register: node_info +''' + + +def _choose_id_value(module): + if module.params['uuid']: + return module.params['uuid'] + if module.params['name']: + return module.params['name'] + return None + + +def main(): + argument_spec = openstack_full_argument_spec( # noqa: F405 + auth_type=dict(required=False), + uuid=dict(required=False), + name=dict(required=False), + mac=dict(required=False), + ironic_url=dict(required=False), + skip_items=dict(required=False, type='list'), + ) + module_kwargs = openstack_module_kwargs() # noqa: F405 + module = AnsibleModule(argument_spec, **module_kwargs) # noqa: F405 + compat = module._name == 'os_ironic_facts' + if compat: + module.deprecate('Using os_ironic_node_info via os_ironic_facts is ' + 'deprecated and may not work correctly') + + if not HAS_SDK: + module.fail_json(msg='openstacksdk is required for this module') + + if (module.params['ironic_url'] and + module.params['auth_type'] in [None, 'None', 'none']): + module.params['auth'] = dict( + endpoint=module.params['ironic_url'] + ) + + # NOTE(dtantsur): the following part is copied more or less verbatim from + # ansible-collections-openstack. + cloud_config = module.params.pop('cloud', None) + try: + if isinstance(cloud_config, dict): + fail_message = ( + "A cloud config dict was provided to the cloud parameter" + " but also a value was provided for {param}. If a cloud" + " config dict is provided, {param} should be" + " excluded.") + for param in ('auth', 'auth_type'): + if module.params[param] is not None: + module.fail_json(msg=fail_message.format(param=param)) + cloud = openstack.connect(**cloud_config) + else: + cloud = openstack.connect( + cloud=cloud_config, + auth_type=module.params['auth_type'], + auth=module.params['auth'], + ) + + if module.params['name'] or module.params['uuid']: + server = cloud.get_machine(_choose_id_value(module)) + elif module.params['mac']: + server = cloud.get_machine_by_mac(module.params['mac']) + else: + module.fail_json(msg="The worlds did not align, " + "the host was not found as " + "no name, uuid, or mac was " + "defined.") + if server: + facts = dict(server) + new_driver_info = dict() + # Rebuild driver_info to remove any password values + # as they will be masked. + for key, value in facts['driver_info'].items(): + if 'password' not in key: + new_driver_info[key] = value + if new_driver_info: + facts['driver_info'] = new_driver_info + + for item in module.params['skip_items']: + if item in facts: + del facts[item] + + # Remove ports and links as they are useless in the ansible + # use context. + if "ports" in facts: + del facts["ports"] + if "links" in facts: + del facts["links"] + + nics = cloud.list_nics_for_machine(server['uuid']) + facts['nics'] = [{'mac': nic['address']} for nic in nics] + + if compat: + # NOTE(dtantsur): this item conflicts with the ansible's own + # network_interface breaking everything. + facts.pop('network_interface', None) + + if compat: + module.exit_json(changed=False, ansible_facts=facts) + else: + module.exit_json(changed=False, node=facts) + + else: + module.fail_json(msg="node not found.") + + except openstack.exceptions.SDKException as e: + module.fail_json(msg=e.message) + + +# this is magic, see lib/ansible/module_common.py +from ansible.module_utils.basic import * # noqa: E402 +from ansible.module_utils.openstack import * # noqa: E402 +main() diff --git a/playbooks/redeploy-dynamic.yaml b/playbooks/redeploy-dynamic.yaml index f0f9298f7..fb943a9f1 100644 --- a/playbooks/redeploy-dynamic.yaml +++ b/playbooks/redeploy-dynamic.yaml @@ -30,26 +30,27 @@ connection: local pre_tasks: - name: "Pull initial ironic facts" - os_ironic_facts: + os_ironic_node_info: auth_type: "{{ auth_type | default(omit) }}" auth: "{{ auth | default(omit) }}" name: "{{ inventory_hostname }}" ironic_url: "{{ ironic_url }}" skip_items: [] + register: node_info roles: - { role: bifrost-unprovision-node-dynamic, when: (provision_state == "active" or provision_state == "deploy failed" or provision_state == "error") and maintenance | bool != true } post_tasks: - name: "Pull ironic facts until provision state available" - os_ironic_facts: + os_ironic_node_info: auth_type: "{{ auth_type | default(omit) }}" auth: "{{ auth | default(omit) }}" name: "{{ inventory_hostname }}" ironic_url: "{{ ironic_url }}" skip_items: [] - register: result - until: provision_state == "available" + register: node_info + until: node_info.node.provision_state == "available" retries: "{{ available_state_wait_retries | default(15) }}" delay: "{{ provision_state_retry_interval | default(20) }}" - hosts: baremetal @@ -61,14 +62,14 @@ - { role: bifrost-deploy-nodes-dynamic, when: provision_state == "available" and maintenance | bool != true } post_tasks: - name: "Pull ironic facts until provision state active" - os_ironic_facts: + os_ironic_node_info: auth_type: "{{ auth_type | default(omit) }}" auth: "{{ auth | default(omit) }}" name: "{{ inventory_hostname }}" ironic_url: "{{ ironic_url }}" skip_items: [] - register: result - until: provision_state == "active" + register: node_info + until: node_info.node.provision_state == "active" retries: "{{ active_state_wait_retries | default(30) }}" delay: "{{ provision_state_retry_interval | default(20) }}" diff --git a/playbooks/roles/bifrost-configdrives-dynamic/tasks/main.yml b/playbooks/roles/bifrost-configdrives-dynamic/tasks/main.yml index 573fb62ee..ddeb4958e 100644 --- a/playbooks/roles/bifrost-configdrives-dynamic/tasks/main.yml +++ b/playbooks/roles/bifrost-configdrives-dynamic/tasks/main.yml @@ -46,7 +46,7 @@ ipv4_subnet_mask: "{{ ipv4_subnet_mask | default('') }}" vlan_id: "{{ vlan_id | default('') }}" network_mtu: "{{ network_mtu | default('1500') }}" - nics: "{{ nics | default(omit) }}" + nics: "{{ node_info.node.nics | default(omit) }}" node_network_data: "{{ node_network_data | default(node_network_info) }}" when: addressing_mode is undefined or "dhcp" not in addressing_mode diff --git a/playbooks/roles/bifrost-configdrives-dynamic/tasks/update_facts_from_ironic.yaml b/playbooks/roles/bifrost-configdrives-dynamic/tasks/update_facts_from_ironic.yaml index c2b67d6b0..6e13acc6f 100644 --- a/playbooks/roles/bifrost-configdrives-dynamic/tasks/update_facts_from_ironic.yaml +++ b/playbooks/roles/bifrost-configdrives-dynamic/tasks/update_facts_from_ironic.yaml @@ -37,7 +37,7 @@ # ironic knows, that we do not know potentially, such as an UUID # should a node have been created without one. - name: "Collecting node facts" - os_ironic_facts: + os_ironic_node_info: cloud: "{{ cloud_name | default(omit) }}" auth_type: "{{ auth_type }}" auth: "{{ auth }}" @@ -46,3 +46,4 @@ name: "{{ name | default() }}" skip_items: - instance_info + register: node_info diff --git a/playbooks/roles/bifrost-ironic-install/README.md b/playbooks/roles/bifrost-ironic-install/README.md index 277c33145..9c4c3c7cb 100644 --- a/playbooks/roles/bifrost-ironic-install/README.md +++ b/playbooks/roles/bifrost-ironic-install/README.md @@ -35,12 +35,11 @@ should be enabled. cleaning: false -The ironic python client and shade libraries can be installed directly from -Git. The default is to utilize pip to install the current versions in pypi, +The ironic python client and openstacksdk libraries can be installed directly +from Git. The default is to utilize pip to install the current versions in pypi, however testing may require master branch or custom patches. openstacksdk_source_install: true -shade_source_install: true Bifrost requires access to the network where nodes are located, in order to provision the nodes. By default, this setting is set to a value for local diff --git a/playbooks/roles/bifrost-ironic-install/defaults/main.yml b/playbooks/roles/bifrost-ironic-install/defaults/main.yml index 9b05de0ff..e518bf118 100644 --- a/playbooks/roles/bifrost-ironic-install/defaults/main.yml +++ b/playbooks/roles/bifrost-ironic-install/defaults/main.yml @@ -13,7 +13,6 @@ staging_drivers_include: false file_url_port: "8080" ironicclient_source_install: false openstacksdk_source_install: true -shade_source_install: true ironicinspector_source_install: true ironicinspectorclient_source_install: false sushy_source_install: false @@ -83,7 +82,6 @@ include_dhcp_server: true dib_git_url: https://opendev.org/openstack/diskimage-builder ironicclient_git_url: https://opendev.org/openstack/python-ironicclient openstacksdk_git_url: https://opendev.org/openstack/openstacksdk -shade_git_url: https://opendev.org/openstack/shade ironic_git_url: https://opendev.org/openstack/ironic staging_drivers_git_url: https://opendev.org/x/ironic-staging-drivers ironicinspector_git_url: https://opendev.org/openstack/ironic-inspector @@ -101,7 +99,6 @@ disable_dnsmasq_dns: False ironic_git_folder: /opt/stack/ironic ironicclient_git_folder: /opt/stack/python-ironicclient openstacksdk_git_folder: /opt/stack/openstacksdk -shade_git_folder: /opt/stack/shade dib_git_folder: /opt/stack/diskimage-builder reqs_git_folder: /opt/stack/requirements upper_constraints_file: "{{ lookup('env', 'UPPER_CONSTRAINTS_FILE') | default(reqs_git_folder + '/upper-constraints.txt', True) }}" diff --git a/playbooks/roles/bifrost-ironic-install/tasks/install.yml b/playbooks/roles/bifrost-ironic-install/tasks/install.yml index 77d94e61a..9d1a89e2c 100644 --- a/playbooks/roles/bifrost-ironic-install/tasks/install.yml +++ b/playbooks/roles/bifrost-ironic-install/tasks/install.yml @@ -26,7 +26,7 @@ - name: "If running in CI, set source install facts just to be sure" set_fact: - shade_source_install: true + openstacksdk_source_install: true ironicclient_source_install: true when: ci_testing | bool == true @@ -123,19 +123,9 @@ include: staging_install.yml when: skip_install is not defined and staging_drivers_include | bool == true -# NOTE(pas-ha) even when install into virtualenv is requested, -# we need to install shade into system for enroll-dynamic to succeed -- block: - - name: install shade - include: pip_install.yml - package=shade - sourcedir={{ shade_git_folder }} - source_install={{ shade_source_install }} - # NOTE(TheJulia): Install openstacksdk since shade wraps to openstacksdk and - # the logic is largely going into openstacksdk as time goes on. - - name: install openstacksdk - include: pip_install.yml - package=openstacksdk - sourcedir={{ openstacksdk_git_folder }} - source_install={{ openstacksdk_source_install }} +- name: install openstacksdk + include: pip_install.yml + package=openstacksdk + sourcedir={{ openstacksdk_git_folder }} + source_install={{ openstacksdk_source_install }} when: skip_install is not defined diff --git a/playbooks/roles/bifrost-openstack-ci-prep/README.md b/playbooks/roles/bifrost-openstack-ci-prep/README.md index 31fe8c91c..f7d5c5295 100644 --- a/playbooks/roles/bifrost-openstack-ci-prep/README.md +++ b/playbooks/roles/bifrost-openstack-ci-prep/README.md @@ -24,8 +24,6 @@ ironic_git_folder: The folder where the ironic codebase has been cloned to. ironicclient_git_folder: The folder where the python-ironicclient code base has been cloned to. -shade_git_folder: The folder where the shade code base has been cloned to. - Dependencies ------------ @@ -53,7 +51,6 @@ of the logic to properly handle an OpenStack CI environment node. ci_testing_zuul: true ironic_git_url: /opt/git/openstack/ironic ironicclient_git_url: /opt/git/openstack/python-ironicclient - shade_git_url: /opt/git/openstack/shade when: lookup('env', 'ZUUL_BRANCH') != "" roles: - { role: bifrost-prep-for-install, when: skip_install is not defined } diff --git a/playbooks/roles/bifrost-prep-for-install/README.md b/playbooks/roles/bifrost-prep-for-install/README.md index 9a5e0aab1..8cce73660 100644 --- a/playbooks/roles/bifrost-prep-for-install/README.md +++ b/playbooks/roles/bifrost-prep-for-install/README.md @@ -28,9 +28,6 @@ ironicclient_git_url: URL for ironicclient, defaults to: openstacksdk_git_url: URL for openstacksdk, defaults to: https://opendev.org/openstack/openstacksdk -shade_git_url: URL for shade, defaults to: - https://opendev.org/openstack/shade - ironic_git_url: URL for ironic, defaults to: https://opendev.org/openstack/ironic @@ -46,9 +43,6 @@ ironic_git_folder: The folder to clone ironic to if missing, default to: openstacksdk_git_folder: The folder to clone openstacksdk to if missing, defaults to: "{{ git_root}}/openstacksdk.git" -shade_git_folder: The folder to clone shade to if missing, defaults to: - "{{ git_root}}/shade.git" - sushy_git_folder: The folder to clone sushy to if missing, default to: "{{ git_root}}/sushy.git" @@ -62,8 +56,6 @@ ironic_git_branch: Branch to install, defaults to the value of git_branch. openstacksdk_git_branch: Branch to install, defaults to the value of git_branch. -shade_git_branch: Branch to install, defaults to the value of git_branch. - dib_git_branch: Branch to install, defaults to "master". ironicinspector_git_branch: Branch to install, defaults to the value of diff --git a/playbooks/roles/bifrost-prep-for-install/defaults/main.yml b/playbooks/roles/bifrost-prep-for-install/defaults/main.yml index 099b7a404..cf41647bb 100644 --- a/playbooks/roles/bifrost-prep-for-install/defaults/main.yml +++ b/playbooks/roles/bifrost-prep-for-install/defaults/main.yml @@ -5,7 +5,6 @@ git_root: "/opt/stack" dib_git_url: https://opendev.org/openstack/diskimage-builder ironicclient_git_url: https://opendev.org/openstack/python-ironicclient openstacksdk_git_url: https://opendev.org/openstack/openstacksdk -shade_git_url: https://opendev.org/openstack/shade ironic_git_url: https://opendev.org/openstack/ironic ironicinspector_git_url: https://opendev.org/openstack/ironic-inspector ironicinspectorclient_git_url: https://opendev.org/openstack/python-ironic-inspector-client @@ -21,7 +20,6 @@ ironic_git_folder: "{{ git_root}}/ironic" ironicinspector_git_folder: "{{ git_root}}/ironic-inspector" ironicinspectorclient_git_folder: "{{ git_root}}/python-ironic-inspector-client" openstacksdk_git_folder: "{{ git_root}}/openstacksdk" -shade_git_folder: "{{ git_root}}/shade" dib_git_folder: "{{ git_root }}/diskimage-builder" reqs_git_folder: "{{ git_root }}/requirements" upper_constraints_file: "{{ lookup('env', 'UPPER_CONSTRAINTS_FILE') | default(reqs_git_folder + '/upper-constraints.txt', True) }}" @@ -35,7 +33,6 @@ git_branch: master ironicclient_git_branch: "{{ git_branch }}" ironic_git_branch: "{{ git_branch }}" openstacksdk_git_branch: "{{ git_branch }}" -shade_git_branch: "{{ git_branch }}" dib_git_branch: master ironicinspector_git_branch: "{{ git_branch }}" ironicinspectorclient_git_branch: "{{ git_branch }}" @@ -63,10 +60,6 @@ bifrost_install_sources: git_url: "{{ openstacksdk_git_url }}" git_branch: "{{ openstacksdk_git_branch }}" name: openstacksdk - - git_folder: "{{ shade_git_folder }}" - git_url: "{{ shade_git_url }}" - git_branch: "{{ shade_git_branch }}" - name: shade - git_folder: "{{ dib_git_folder }}" git_url: "{{ dib_git_url }}" git_branch: "{{ dib_git_branch }}" diff --git a/playbooks/roles/ironic-enroll-dynamic/README.md b/playbooks/roles/ironic-enroll-dynamic/README.md index 9099bb479..8b1e93438 100644 --- a/playbooks/roles/ironic-enroll-dynamic/README.md +++ b/playbooks/roles/ironic-enroll-dynamic/README.md @@ -8,9 +8,7 @@ Requirements ------------ This role is dependent upon the os-ironic ansible module, which is dependent -upon shade (https://opendev.org/openstack/shade/), which in -this case is presently dependent upon the Ironic Python Client Library -(https://opendev.org/openstack/python-ironicclient/). +upon openstacksdk (https://opendev.org/openstack/openstacksdk/). Role Variables -------------- diff --git a/playbooks/roles/ironic-inspect-node/README.md b/playbooks/roles/ironic-inspect-node/README.md index e36464726..6b570db21 100644 --- a/playbooks/roles/ironic-inspect-node/README.md +++ b/playbooks/roles/ironic-inspect-node/README.md @@ -29,8 +29,8 @@ cloud_name: Optional: String value defining a clouds.yaml entry for the ansible module to leverage. inspection_wait_timeout: Integer value in seconds, defaults to 1800. This value may need to be adjusted if the underlying - shade library's default timeout is insufficient for - a node to perform an inspection sequence with. + openstacksdk library's default timeout is insufficient + for a node to perform an inspection sequence with. The timeout assumption in the library was based upon there being three phases to complete an inspection sequence, BIOS POST, (i)PXE, diff --git a/playbooks/test-bifrost.yaml b/playbooks/test-bifrost.yaml index f5f27e7d5..0cc70a9d7 100644 --- a/playbooks/test-bifrost.yaml +++ b/playbooks/test-bifrost.yaml @@ -32,7 +32,6 @@ ironic_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack/ironic" ironicclient_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack/python-ironicclient" openstacksdk_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack/openstacksdk" - shade_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack/shade" dib_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack/diskimage-builder" ironicinspector_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack/ironic-inspector" ironicinspectorclient_git_url: "{{ lookup('env', 'WORKSPACE') }}/openstack/python-ironic-inspector-client" diff --git a/releasenotes/notes/no-shade-b861f699b8a9919f.yaml b/releasenotes/notes/no-shade-b861f699b8a9919f.yaml new file mode 100644 index 000000000..3aa730bc7 --- /dev/null +++ b/releasenotes/notes/no-shade-b861f699b8a9919f.yaml @@ -0,0 +1,8 @@ +--- +upgrade: + - | + The shade library is no longer used, nor installed by default. +deprecations: + - | + The ``os_ironic_facts`` module is deprecated. Please use + ``os_ironic_node_info`` that returns information in the "node" parameter. diff --git a/test-requirements.txt b/test-requirements.txt index e806fc180..08571a142 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -15,3 +15,4 @@ PyYAML>=3.12 # MIT Pygments>=2.2.0 # BSD license flake8-import-order>=0.17.1 # LGPLv3 +openstacksdk>=0.37.0 # Apache-2.0 diff --git a/zuul.d/bifrost-jobs.yaml b/zuul.d/bifrost-jobs.yaml index 4018adef3..9aefed054 100644 --- a/zuul.d/bifrost-jobs.yaml +++ b/zuul.d/bifrost-jobs.yaml @@ -26,7 +26,6 @@ - openstack/python-ironic-inspector-client - openstack/python-ironicclient - openstack/requirements - - openstack/shade - openstack/sushy - x/ironic-staging-drivers