Remove support for the legacy CSV format
Change-Id: I11f4976fbd48e552990f2a1890cea7201bbbb024
This commit is contained in:
parent
3bf9631ae5
commit
790f81c3a8
@ -15,7 +15,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
@ -65,10 +64,9 @@ of desired groups. Moreover, users can override the default 'baremetal'
|
||||
group by assigning a list of default groups to the test_vm_default_group
|
||||
variable.
|
||||
|
||||
Presently, the base mode of operation reads a CSV file in the format
|
||||
Presently, the base mode of operation reads a JSON/YAML file in the format
|
||||
originally utilized by bifrost and returns structured JSON that is
|
||||
interpreted by Ansible. This has since been extended to support the
|
||||
parsing of JSON and YAML data if they are detected in the file.
|
||||
interpreted by Ansible.
|
||||
|
||||
Conceivably, this inventory module can be extended to allow for direct
|
||||
processing of inventory data from other data sources such as a configuration
|
||||
@ -78,7 +76,7 @@ user experience.
|
||||
How to use?
|
||||
-----------
|
||||
|
||||
export BIFROST_INVENTORY_SOURCE=/tmp/baremetal.[csv|json|yaml]
|
||||
export BIFROST_INVENTORY_SOURCE=/tmp/baremetal.[json|yaml]
|
||||
ansible-playbook playbook.yaml -i inventory/bifrost_inventory.py
|
||||
|
||||
One can also just directly invoke bifrost_inventory.py in order to see the
|
||||
@ -151,9 +149,6 @@ opts = [
|
||||
cfg.BoolOpt('list',
|
||||
default=True,
|
||||
help='List active hosts'),
|
||||
cfg.BoolOpt('convertcsv',
|
||||
default=False,
|
||||
help='Converts a CSV inventory to JSON'),
|
||||
]
|
||||
|
||||
|
||||
@ -176,24 +171,13 @@ def _prepare_inventory():
|
||||
return (groups, hostvars)
|
||||
|
||||
|
||||
def _val_or_none(array, location):
|
||||
"""Return any value that has a length"""
|
||||
try:
|
||||
if len(array[location]) > 0:
|
||||
return array[location]
|
||||
return None
|
||||
except IndexError:
|
||||
LOG.debug("Out of range value encountered. Requested "
|
||||
"field %s Had: %s", location, array)
|
||||
|
||||
|
||||
def _process_baremetal_data(data_source, groups, hostvars):
|
||||
"""Process data through as pre-formatted data"""
|
||||
with open(data_source, 'rb') as file_object:
|
||||
try:
|
||||
file_data = yaml.safe_load(file_object)
|
||||
except Exception as e:
|
||||
LOG.debug("Failed to parse JSON or YAML: %s", e)
|
||||
LOG.error("Failed to parse JSON or YAML: %s", e)
|
||||
raise Exception("Failed to parse JSON or YAML")
|
||||
|
||||
node_names = os.environ.get('BIFROST_NODE_NAMES', None)
|
||||
@ -230,100 +214,6 @@ def _process_baremetal_data(data_source, groups, hostvars):
|
||||
return (groups, hostvars)
|
||||
|
||||
|
||||
def _process_baremetal_csv(data_source, groups, hostvars):
|
||||
"""Process legacy baremetal.csv format"""
|
||||
node_names = os.environ.get('BIFROST_NODE_NAMES', None)
|
||||
if node_names:
|
||||
node_names = node_names.split(',')
|
||||
|
||||
with open(data_source, 'r') as file_data:
|
||||
for row in csv.reader(file_data, delimiter=','):
|
||||
if not row:
|
||||
break
|
||||
if len(row) == 1:
|
||||
LOG.debug("Single entry line found when attempting "
|
||||
"to parse CSV file contents. Breaking "
|
||||
"out of processing loop.")
|
||||
raise Exception("Invalid CSV file format detected, "
|
||||
"line ends with a single element")
|
||||
host = {}
|
||||
driver = None
|
||||
driver_info = {}
|
||||
power = {}
|
||||
properties = {}
|
||||
host['nics'] = [{
|
||||
'mac': _val_or_none(row, 0)}]
|
||||
# Temporary variables for ease of reading
|
||||
management_username = _val_or_none(row, 1)
|
||||
management_password = _val_or_none(row, 2)
|
||||
management_address = _val_or_none(row, 3)
|
||||
|
||||
properties['cpus'] = _val_or_none(row, 4)
|
||||
properties['ram'] = _val_or_none(row, 5)
|
||||
properties['disk_size'] = _val_or_none(row, 6)
|
||||
# Default CPU Architecture
|
||||
properties['cpu_arch'] = "x86_64"
|
||||
host['uuid'] = _val_or_none(row, 9)
|
||||
host['name'] = _val_or_none(row, 10)
|
||||
|
||||
if node_names and host['name'] not in node_names:
|
||||
continue
|
||||
|
||||
host['host_groups'] = ["baremetal"]
|
||||
host['ipv4_address'] = _val_or_none(row, 11)
|
||||
if ('ipv4_address' not in host or
|
||||
not host['ipv4_address']):
|
||||
host['addressing_mode'] = "dhcp"
|
||||
host['provisioning_ipv4_address'] = None
|
||||
else:
|
||||
host['ansible_ssh_host'] = host['ipv4_address']
|
||||
# Note(TheJulia): We can't assign ipv4_address if we are
|
||||
# using DHCP.
|
||||
if (len(row) > 17 and 'addressing_mode' not in host):
|
||||
host['provisioning_ipv4_address'] = row[18]
|
||||
else:
|
||||
host['provisioning_ipv4_address'] = host['ipv4_address']
|
||||
|
||||
# Default Driver unless otherwise defined or determined.
|
||||
host['driver'] = "ipmi"
|
||||
|
||||
if len(row) > 15:
|
||||
driver = _val_or_none(row, 16)
|
||||
if driver:
|
||||
host['driver'] = driver
|
||||
|
||||
if "ipmi" in host['driver']:
|
||||
# Set ipmi by default
|
||||
host['driver'] = "ipmi"
|
||||
power['ipmi_address'] = management_address
|
||||
power['ipmi_username'] = management_username
|
||||
power['ipmi_password'] = management_password
|
||||
if len(row) > 12:
|
||||
power['ipmi_target_channel'] = _val_or_none(row, 12)
|
||||
power['ipmi_target_address'] = _val_or_none(row, 13)
|
||||
if (power['ipmi_target_channel'] and
|
||||
power['ipmi_target_address']):
|
||||
power['ipmi_bridging'] = 'single'
|
||||
if len(row) > 14:
|
||||
power['ipmi_transit_channel'] = _val_or_none(row, 14)
|
||||
power['ipmi_transit_address'] = _val_or_none(row, 15)
|
||||
if (power['ipmi_transit_channel'] and
|
||||
power['ipmi_transit_address']):
|
||||
power['ipmi_bridging'] = 'dual'
|
||||
|
||||
# Group variables together under host.
|
||||
# NOTE(TheJulia): Given the split that this demonstrates, where
|
||||
# deploy details could possible be imported from a future
|
||||
# inventory file format
|
||||
driver_info['power'] = power
|
||||
host['driver_info'] = driver_info
|
||||
host['properties'] = properties
|
||||
|
||||
groups['baremetal']['hosts'].append(host['name'])
|
||||
hostvars.update({host['name']: host})
|
||||
return (groups, hostvars)
|
||||
|
||||
|
||||
def _process_sdk(groups, hostvars):
|
||||
"""Retrieve inventory utilizing OpenStackSDK."""
|
||||
# NOTE(dtantsur): backward compatibility
|
||||
@ -401,19 +291,10 @@ def main():
|
||||
groups,
|
||||
hostvars)
|
||||
except Exception as e:
|
||||
LOG.debug("File does not appear to be JSON or YAML - %s", e)
|
||||
try:
|
||||
(groups, hostvars) = _process_baremetal_csv(
|
||||
data_source,
|
||||
groups,
|
||||
hostvars)
|
||||
except Exception as e:
|
||||
LOG.debug("CSV fallback processing failed, "
|
||||
"received: %s", e)
|
||||
LOG.error("BIFROST_INVENTORY_SOURCE does not define "
|
||||
"a file that could be processed: "
|
||||
"Tried JSON, YAML, and CSV formats")
|
||||
sys.exit(1)
|
||||
LOG.error("BIFROST_INVENTORY_SOURCE does not define "
|
||||
"a file that could be processed: %s."
|
||||
"Tried JSON and YAML formats", e)
|
||||
sys.exit(1)
|
||||
elif "ironic" in data_source:
|
||||
if SDK_LOADED:
|
||||
(groups, hostvars) = _process_sdk(groups, hostvars)
|
||||
@ -440,12 +321,9 @@ def main():
|
||||
|
||||
# General Data Conversion
|
||||
|
||||
if not config.convertcsv:
|
||||
inventory = {'_meta': {'hostvars': hostvars}}
|
||||
inventory.update(groups)
|
||||
print(json.dumps(inventory, indent=2))
|
||||
else:
|
||||
print(json.dumps(hostvars, indent=2))
|
||||
inventory = {'_meta': {'hostvars': hostvars}}
|
||||
inventory.update(groups)
|
||||
print(json.dumps(inventory, indent=2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -29,173 +29,6 @@ class TestBifrostInventoryFunctional(base.TestCase):
|
||||
self.maxDiff = None
|
||||
super(TestBifrostInventoryFunctional, self).setUp()
|
||||
|
||||
def test_csv_file_conversion_multiline_general(self):
|
||||
# NOTE(TheJulia): While this is a massive amount of input
|
||||
# and resulting output that is parsed as part of this
|
||||
# and similar tests, we need to ensure consistency,
|
||||
# and that is largely what this test is geared to ensure.
|
||||
CSV = """00:01:02:03:04:05,root,undefined,192.0.2.2,1,8192,512,
|
||||
unused,,00000000-0000-0000-0000-000000000001,hostname0,
|
||||
192.168.1.2,,,,|
|
||||
00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024,
|
||||
unused,,00000000-0000-0000-0000-000000000002,hostname1,
|
||||
192.168.1.3,,,,,ipmi""".replace('\n', '').replace('|', '\n')
|
||||
expected_hostvars = """{"hostname1":
|
||||
{"uuid": "00000000-0000-0000-0000-000000000002", "driver": "ipmi",
|
||||
"name": "hostname1", "ipv4_address": "192.168.1.3",
|
||||
"provisioning_ipv4_address": "192.168.1.3" ,"ansible_ssh_host":
|
||||
"192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3",
|
||||
"ipmi_password": "undefined", "ipmi_username": "root",
|
||||
"ipmi_target_address": null, "ipmi_target_channel": null,
|
||||
"ipmi_transit_address": null, "ipmi_transit_channel": null}}, "nics":
|
||||
[{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch":
|
||||
"x86_64", "disk_size": "1024", "cpus": "2"}, "host_groups": ["baremetal"]},
|
||||
"hostname0":
|
||||
{"uuid": "00000000-0000-0000-0000-000000000001", "driver": "ipmi",
|
||||
"name": "hostname0", "ipv4_address": "192.168.1.2",
|
||||
"provisioning_ipv4_address": "192.168.1.2", "ansible_ssh_host":
|
||||
"192.168.1.2", "driver_info": {"power": {"ipmi_address": "192.0.2.2",
|
||||
"ipmi_password": "undefined", "ipmi_username": "root",
|
||||
"ipmi_target_address": null, "ipmi_target_channel": null,
|
||||
"ipmi_transit_address": null, "ipmi_transit_channel": null}}, "nics":
|
||||
[{"mac": "00:01:02:03:04:05"}], "properties": {"ram": "8192",
|
||||
"cpu_arch": "x86_64", "disk_size": "512", "cpus": "1"},
|
||||
"host_groups": ["baremetal"]}}""".replace('\n', '')
|
||||
expected_groups = """{"baremetal": {"hosts": ["hostname0",
|
||||
"hostname1"]}, "localhost": {"hosts": ["127.0.0.1"]}}""".replace('\n', '')
|
||||
|
||||
(groups, hostvars) = utils.bifrost_csv_conversion(CSV)
|
||||
self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars)
|
||||
self.assertDictEqual(json.loads(expected_groups), groups)
|
||||
|
||||
def test_csv_file_conversion_ipmi_dual_bridging(self):
|
||||
CSV = """00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024,
|
||||
unused,,00000000-0000-0000-0000-000000000002,hostname1,
|
||||
192.168.1.3,10,20,30,40,ipmi""".replace('\n', '').replace('|', '\n')
|
||||
|
||||
expected_hostvars = """{"hostname1":
|
||||
{"uuid": "00000000-0000-0000-0000-000000000002", "driver": "ipmi",
|
||||
"name": "hostname1", "ipv4_address": "192.168.1.3",
|
||||
"provisioning_ipv4_address": "192.168.1.3", "ansible_ssh_host":
|
||||
"192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3",
|
||||
"ipmi_password": "undefined", "ipmi_username": "root",
|
||||
"ipmi_target_address": "20", "ipmi_target_channel": "10",
|
||||
"ipmi_transit_address": "40", "ipmi_transit_channel": "30",
|
||||
"ipmi_bridging": "dual"}}, "nics":
|
||||
[{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch":
|
||||
"x86_64", "disk_size": "1024", "cpus": "2"},
|
||||
"host_groups": ["baremetal"]}}""".replace('\n', '')
|
||||
|
||||
expected_groups = """{"baremetal": {"hosts": ["hostname1"]},
|
||||
"localhost": {"hosts": ["127.0.0.1"]}}""".replace('\n', '')
|
||||
|
||||
(groups, hostvars) = utils.bifrost_csv_conversion(CSV)
|
||||
self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars)
|
||||
self.assertDictEqual(json.loads(expected_groups), groups)
|
||||
|
||||
def test_csv_file_conversion_ipmi_single_bridging(self):
|
||||
CSV = """00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024,
|
||||
unused,,00000000-0000-0000-0000-000000000002,hostname1,
|
||||
192.168.1.3,10,20,,,ipmi""".replace('\n', '').replace('|', '\n')
|
||||
|
||||
expected_hostvars = """{"hostname1":
|
||||
{"uuid": "00000000-0000-0000-0000-000000000002", "driver": "ipmi",
|
||||
"name": "hostname1", "ipv4_address": "192.168.1.3",
|
||||
"provisioning_ipv4_address": "192.168.1.3", "ansible_ssh_host":
|
||||
"192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3",
|
||||
"ipmi_password": "undefined", "ipmi_username": "root",
|
||||
"ipmi_target_address": "20", "ipmi_target_channel": "10",
|
||||
"ipmi_transit_address": null, "ipmi_transit_channel": null,
|
||||
"ipmi_bridging": "single"}}, "nics":
|
||||
[{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch":
|
||||
"x86_64", "disk_size": "1024", "cpus": "2"},
|
||||
"host_groups": ["baremetal"]}}""".replace('\n', '')
|
||||
|
||||
(groups, hostvars) = utils.bifrost_csv_conversion(CSV)
|
||||
self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars)
|
||||
|
||||
def test_csv_file_conversion_dhcp(self):
|
||||
CSV = """00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024,
|
||||
unused,,00000000-0000-0000-0000-000000000002,hostname1
|
||||
,,,,,,ipmi""".replace('\n', '').replace('|', '\n')
|
||||
|
||||
expected_hostvars = """{"hostname1":
|
||||
{"uuid": "00000000-0000-0000-0000-000000000002", "driver": "ipmi",
|
||||
"name": "hostname1", "addressing_mode": "dhcp", "ipv4_address": null,
|
||||
"provisioning_ipv4_address": null,
|
||||
"driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password":
|
||||
"undefined", "ipmi_username": "root", "ipmi_target_address": null,
|
||||
"ipmi_target_channel": null, "ipmi_transit_address": null,
|
||||
"ipmi_transit_channel": null}}, "nics":
|
||||
[{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch":
|
||||
"x86_64", "disk_size": "1024", "cpus": "2"},
|
||||
"host_groups": ["baremetal"]}}""".replace('\n', '')
|
||||
|
||||
(groups, hostvars) = utils.bifrost_csv_conversion(CSV)
|
||||
self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars)
|
||||
|
||||
def test_csv_json_reconsumability_dhcp(self):
|
||||
# Note(TheJulia) This intentionally takes CSV data, converts it
|
||||
# and then attempts reconsumption of the same data through the
|
||||
# JSON/YAML code path of Bifrost to ensure that the output
|
||||
# is identical.
|
||||
CSV = """00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024,
|
||||
unused,,00000000-0000-0000-0000-000000000002,hostname1
|
||||
,,,,,,ipmi""".replace('\n', '')
|
||||
|
||||
expected_hostvars = """{"hostname1":
|
||||
{"uuid": "00000000-0000-0000-0000-000000000002", "driver": "ipmi",
|
||||
"name": "hostname1", "addressing_mode": "dhcp", "ipv4_address": null,
|
||||
"provisioning_ipv4_address": null,
|
||||
"driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password":
|
||||
"undefined", "ipmi_username": "root", "ipmi_target_address": null,
|
||||
"ipmi_target_channel": null, "ipmi_transit_address": null,
|
||||
"ipmi_transit_channel": null}}, "nics":
|
||||
[{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch":
|
||||
"x86_64", "disk_size": "1024", "cpus": "2"},
|
||||
"host_groups": ["baremetal"]}}""".replace('\n', '')
|
||||
|
||||
(groups, hostvars) = utils.bifrost_csv_conversion(CSV)
|
||||
self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars)
|
||||
(groups, hostvars) = utils.bifrost_data_conversion(
|
||||
json.dumps(hostvars))
|
||||
self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars)
|
||||
|
||||
def test_csv_json_reconsumability_general(self):
|
||||
CSV = """00:01:02:03:04:05,root,undefined,192.0.2.2,1,8192,512,
|
||||
unused,,00000000-0000-0000-0000-000000000001,hostname0,
|
||||
192.168.1.2,,,,|
|
||||
00:01:02:03:04:06,root,undefined,192.0.2.3,2,8192,1024,
|
||||
unused,,00000000-0000-0000-0000-000000000002,hostname1,
|
||||
192.168.1.3,,,,,ipmi""".replace('\n', '').replace('|', '\n')
|
||||
expected_hostvars = """{"hostname1":
|
||||
{"uuid": "00000000-0000-0000-0000-000000000002", "driver": "ipmi",
|
||||
"name": "hostname1", "ipv4_address": "192.168.1.3", "ansible_ssh_host":
|
||||
"192.168.1.3", "provisioning_ipv4_address": "192.168.1.3",
|
||||
"driver_info": {"power": {"ipmi_address": "192.0.2.3",
|
||||
"ipmi_password": "undefined", "ipmi_username": "root",
|
||||
"ipmi_target_address": null, "ipmi_target_channel": null,
|
||||
"ipmi_transit_address": null, "ipmi_transit_channel": null}}, "nics":
|
||||
[{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch":
|
||||
"x86_64", "disk_size": "1024", "cpus": "2"}, "host_groups": ["baremetal"]},
|
||||
"hostname0":
|
||||
{"uuid": "00000000-0000-0000-0000-000000000001", "driver": "ipmi",
|
||||
"name": "hostname0", "ipv4_address": "192.168.1.2", "ansible_ssh_host":
|
||||
"192.168.1.2", "provisioning_ipv4_address": "192.168.1.2",
|
||||
"driver_info": {"power": {"ipmi_address": "192.0.2.2",
|
||||
"ipmi_password": "undefined", "ipmi_username": "root",
|
||||
"ipmi_target_address": null, "ipmi_target_channel": null,
|
||||
"ipmi_transit_address": null, "ipmi_transit_channel": null}}, "nics":
|
||||
[{"mac": "00:01:02:03:04:05"}], "properties": {"ram": "8192",
|
||||
"cpu_arch": "x86_64", "disk_size": "512", "cpus": "1"},
|
||||
"host_groups": ["baremetal"]}}""".replace('\n', '')
|
||||
|
||||
(groups, hostvars) = utils.bifrost_csv_conversion(CSV)
|
||||
self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars)
|
||||
(groups, hostvars) = utils.bifrost_data_conversion(
|
||||
json.dumps(hostvars))
|
||||
self.assertDictEqual(json.loads(str(expected_hostvars)), hostvars)
|
||||
|
||||
def test_yaml_to_json_conversion(self):
|
||||
# Note(TheJulia) Ultimately this is just ensuring
|
||||
# that we get the same output when we pass something
|
||||
|
@ -37,13 +37,6 @@ class TestBifrostInventoryUnit(base.TestCase):
|
||||
localhost_value = dict(hosts=["127.0.0.1"])
|
||||
self.assertDictEqual(localhost_value, groups['localhost'])
|
||||
|
||||
def test__val_or_none(self):
|
||||
array = ['no', '', 'yes']
|
||||
self.assertEqual('no', inventory._val_or_none(array, 0))
|
||||
self.assertIsNone(inventory._val_or_none(array, 1))
|
||||
self.assertEqual('yes', inventory._val_or_none(array, 2))
|
||||
self.assertIsNone(inventory._val_or_none(array, 4))
|
||||
|
||||
@mock.patch.object(openstack, 'connect', autospec=True)
|
||||
def test__process_sdk(self, mock_sdk):
|
||||
(groups, hostvars) = inventory._prepare_inventory()
|
||||
|
@ -33,18 +33,6 @@ def temporary_file(file_data):
|
||||
file.close()
|
||||
|
||||
|
||||
def bifrost_csv_conversion(csv_data):
|
||||
# TODO(TheJulia): To call prep feels like a bug and should be fixed.
|
||||
(groups, hostvars) = inventory._prepare_inventory()
|
||||
with temporary_file(csv_data) as file:
|
||||
(groups, hostvars) = inventory._process_baremetal_csv(
|
||||
file,
|
||||
groups,
|
||||
hostvars)
|
||||
# NOTE(TheJulia): Returning separately so the file is closed first
|
||||
return (groups, hostvars)
|
||||
|
||||
|
||||
def bifrost_data_conversion(data):
|
||||
(groups, hostvars) = inventory._prepare_inventory()
|
||||
with temporary_file(data) as file:
|
||||
|
@ -61,12 +61,7 @@ your hardware. When utilizing the dynamic inventory module and
|
||||
accompanying roles the inventory can be supplied in one of three ways,
|
||||
all of which ultimately translate to JSON data that Ansible parses.
|
||||
|
||||
The original method is to utilize a CSV file. This format is covered below in
|
||||
the `Legacy CSV File Format`_ section. This has a number of limitations, but
|
||||
does allow a user to bulk load hardware from an inventory list with minimal
|
||||
data transformations.
|
||||
|
||||
The newer method is to utilize a JSON or YAML document which the inventory
|
||||
The current method is to utilize a JSON or YAML document which the inventory
|
||||
parser will convert and provide to Ansible.
|
||||
|
||||
In order to use, you will need to define the environment variable
|
||||
@ -74,18 +69,6 @@ In order to use, you will need to define the environment variable
|
||||
execute Ansible utilizing the ``bifrost_inventory.py`` file as the data
|
||||
source.
|
||||
|
||||
Conversion from CSV to JSON formats
|
||||
-----------------------------------
|
||||
|
||||
The ``inventory/bifrost_inventory.py`` program additionally features a
|
||||
mode that allows a user to convert a CSV file to the JSON data format
|
||||
utilizing a ``--convertcsv`` command line setting when directly invoked.
|
||||
|
||||
Example::
|
||||
|
||||
export BIFROST_INVENTORY_SOURCE=/tmp/baremetal.csv
|
||||
inventory/bifrost_inventory.py --convertcsv >/tmp/baremetal.json
|
||||
|
||||
JSON file format
|
||||
----------------
|
||||
|
||||
@ -135,41 +118,6 @@ in an ``instance_info`` variable.
|
||||
Examples utilizing JSON and YAML formatting, along host specific variable
|
||||
injection can be found in the ``playbooks/inventory/`` folder.
|
||||
|
||||
Legacy CSV file format
|
||||
----------------------
|
||||
|
||||
The CSV file has the following columns:
|
||||
|
||||
0. MAC Address
|
||||
1. Management username
|
||||
2. Management password
|
||||
3. Management Address
|
||||
4. CPU Count
|
||||
5. Memory size in MB
|
||||
6. Disk Storage in GB
|
||||
7. Flavor (Not Used)
|
||||
8. Type (Not Used)
|
||||
9. Host UUID
|
||||
10. Host or Node name
|
||||
11. Host IP Address to be set
|
||||
12. ``ipmi_target_channel`` - Requires: ``ipmi_bridging`` set to single
|
||||
13. ``ipmi_target_address`` - Requires: ``ipmi_bridging`` set to single
|
||||
14. ``ipmi_transit_channel`` - Requires: ``ipmi_bridging`` set to dual
|
||||
15. ``ipmi_transit_address`` - Requires: ``ipmi_bridging`` set to dual
|
||||
16. ironic driver
|
||||
17. Host provisioning IP Address
|
||||
|
||||
Example definition::
|
||||
|
||||
00:11:22:33:44:55,root,undefined,192.168.122.1,1,8192,512,NA,NA,aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee,hostname_100,192.168.2.100,,,,ipmi,10.0.0.9
|
||||
|
||||
This file format is fairly flexible and can be easily modified
|
||||
although the enrollment and deployment playbooks utilize the model
|
||||
of a host per line model in order to process through the entire
|
||||
list, as well as reference the specific field items.
|
||||
|
||||
An example file can be found at: ``playbooks/inventory/baremetal.csv.example``
|
||||
|
||||
.. _enroll:
|
||||
|
||||
How this works?
|
||||
|
@ -12,8 +12,8 @@
|
||||
# interfaces.
|
||||
#
|
||||
# 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
|
||||
# another data source such as a YAML or JSON file formats to query ironic,
|
||||
# and the example role conditionals below to query current status and
|
||||
# deploy to nodes.
|
||||
---
|
||||
- hosts: localhost
|
||||
|
@ -8,7 +8,7 @@
|
||||
# to 'active' state.
|
||||
#
|
||||
# To utilize:
|
||||
# export BIFROST_INVENTORY_SOURCE=<path to json, csv, or yaml data source>
|
||||
# export BIFROST_INVENTORY_SOURCE=<path to json or yaml data source>
|
||||
# ansible-playbook -vvvv -i inventory/bifrost_inventory.py redeploy-dynamic.yaml
|
||||
# NOTE: 'ironic' may be used as the data source, in which case ironic will
|
||||
# will be queried for all the nodes.
|
||||
|
@ -26,15 +26,8 @@ as extra-vars instead.
|
||||
Role Variables
|
||||
--------------
|
||||
|
||||
baremetal_csv_file: Deprecated. CSV file format is deprecated, and
|
||||
this variable will be removed in the Queens release.
|
||||
Use 'baremetal_json_file' variable instead.
|
||||
Default is undefined. If defined, its value will be
|
||||
used for 'baremetal_json_file' variable (see below),
|
||||
although file created will still be in JSON format.
|
||||
|
||||
baremetal_json_file: Defaults to '/tmp/baremetal.json' but will be overridden
|
||||
by 'baremetal_csv_file' if that is defined.
|
||||
baremetal_json_file: Bare metal inventory file. Defaults to
|
||||
'/tmp/baremetal.json'.
|
||||
|
||||
test_vm_memory_size: Tunable setting to allow a user to define a specific
|
||||
amount of RAM in MB to allocate to guest/test VMs.
|
||||
|
@ -12,20 +12,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
---
|
||||
- name: produce warning when csv file is defined
|
||||
debug:
|
||||
msg: >
|
||||
"WARNING - Variable 'baremetal_csv_file' is deprecated.
|
||||
For backward compatibility, its value will be used as path for
|
||||
file to write data for created 'virtual' baremetal nodes,
|
||||
but the file will be JSON formatted."
|
||||
when: baremetal_csv_file is defined
|
||||
|
||||
- name: override baremetal_json_file with csv file path
|
||||
set_fact:
|
||||
baremetal_json_file: "{{ baremetal_csv_file }}"
|
||||
when: baremetal_csv_file is defined
|
||||
|
||||
# NOTE(cinerama) openSUSE Tumbleweed & Leap have different distribution
|
||||
# IDs which are not currently accounted for in Ansible, so adjust facts
|
||||
# so we can have shared defaults for the whole SuSE family.
|
||||
|
@ -19,23 +19,6 @@ import os
|
||||
import sys
|
||||
|
||||
|
||||
def _load_data_from_csv(path):
|
||||
with open(path) as csvfile:
|
||||
csvdata = [row for row in csv.reader(csvfile)]
|
||||
inventory = {}
|
||||
# NOTE(pas-ha) convert to structure similar to JSON inventory
|
||||
for entry in csvdata:
|
||||
mac = entry[0]
|
||||
hostname = entry[10]
|
||||
ip = entry[11]
|
||||
inventory[hostname] = {
|
||||
'nics': [{'mac': mac}],
|
||||
'name': hostname,
|
||||
'ipv4_address': ip
|
||||
}
|
||||
return inventory
|
||||
|
||||
|
||||
def _load_data_from_json(path):
|
||||
with open(path) as jsonfile:
|
||||
inventory = json.load(jsonfile)
|
||||
@ -55,13 +38,6 @@ def main(argv):
|
||||
# load data from json file
|
||||
if os.path.exists('/tmp/baremetal.json'):
|
||||
inventory = _load_data_from_json('/tmp/baremetal.json')
|
||||
# load data from csv file
|
||||
elif os.path.exists('/tmp/baremetal.csv'):
|
||||
try:
|
||||
inventory = _load_data_from_csv('/tmp/baremetal.csv')
|
||||
except Exception:
|
||||
# try load *.csv as json for backward compatibility
|
||||
inventory = _load_data_from_json('/tmp/baremetal.csv')
|
||||
else:
|
||||
print('ERROR: Inventory file has not been generated')
|
||||
sys.exit(1)
|
||||
|
@ -6,17 +6,6 @@
|
||||
become: yes
|
||||
gather_facts: yes
|
||||
pre_tasks:
|
||||
- name: "Warn if baremetal_csv_file is defined"
|
||||
debug:
|
||||
msg: >
|
||||
"WARNING - 'baremetal_csv_file' variable is defined.
|
||||
Its use is deprecated. The file created will be in JSON format.
|
||||
Use 'baremetal_json_file' variable instead."
|
||||
when: baremetal_csv_file is defined
|
||||
- name: "Re-set baremetal json to csv file if defined"
|
||||
set_fact:
|
||||
baremetal_json_file: "{{ baremetal_csv_file }}"
|
||||
when: baremetal_csv_file is defined
|
||||
- name: "Set default baremetal.json file if not already defined"
|
||||
set_fact:
|
||||
baremetal_json_file: "/tmp/baremetal.json"
|
||||
|
@ -126,7 +126,7 @@
|
||||
- role: bifrost-prepare-for-test-dynamic
|
||||
|
||||
# The testvm Host group is added by bifrost-prepare-for-test based
|
||||
# on the contents of the CSV file.
|
||||
# on the contents of the JSON file.
|
||||
- hosts: test
|
||||
name: "Tests connectivity to the VM"
|
||||
become: no
|
||||
|
5
releasenotes/notes/no-csv-b7f149e88aba1b85.yaml
Normal file
5
releasenotes/notes/no-csv-b7f149e88aba1b85.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Support for the legacy CSV inventory format has been removed, only JSON and
|
||||
YAML are supported now.
|
Loading…
Reference in New Issue
Block a user