Implementation of the Baremental import command
Change-Id: I2db67a7deea8367e660275ee637ab766587d223b
This commit is contained in:
parent
7182f50cd2
commit
d6a3d98ed9
|
@ -15,4 +15,5 @@
|
|||
import pbr.version
|
||||
|
||||
|
||||
__version__ = pbr.version.VersionInfo('python-rdomanager-oscplugin').version_string()
|
||||
__version__ = pbr.version.VersionInfo(
|
||||
'python-rdomanager-oscplugin').version_string()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
import logging
|
||||
|
||||
from ironicclient import client as ironic_client
|
||||
from openstackclient.common import utils
|
||||
|
||||
|
||||
|
@ -27,28 +28,10 @@ DEFAULT_RDOMANAGER_OSCPLUGIN_API_VERSION = '1'
|
|||
# Required by the OSC plugin interface
|
||||
API_NAME = 'rdomanager_oscplugin'
|
||||
API_VERSION_OPTION = 'os_rdomanager_oscplugin_api_version'
|
||||
API_VERSIONS = {
|
||||
'1': 'rdomanager_oscplugin.plugin.EmptyClient',
|
||||
}
|
||||
|
||||
|
||||
# Required by the OSC plugin interface
|
||||
def make_client(instance):
|
||||
"""Returns a client to the ClientManager
|
||||
|
||||
Called to instantiate the requested client version. instance has
|
||||
any available auth info that may be required to prepare the client.
|
||||
|
||||
:param ClientManager instance: The ClientManager that owns the new client
|
||||
"""
|
||||
plugin_client = utils.get_client_class(
|
||||
API_NAME,
|
||||
instance._api_version[API_NAME],
|
||||
API_VERSIONS)
|
||||
LOG.debug('Instantiating plugin client: %s' % plugin_client)
|
||||
|
||||
client = plugin_client()
|
||||
return client
|
||||
return ClientWrapper(instance)
|
||||
|
||||
|
||||
# Required by the OSC plugin interface
|
||||
|
@ -74,7 +57,24 @@ def build_option_parser(parser):
|
|||
return parser
|
||||
|
||||
|
||||
class EmptyClient(object):
|
||||
"""The ultimate placeholder"""
|
||||
class ClientWrapper(object):
|
||||
|
||||
pass
|
||||
def __init__(self, instace):
|
||||
self._instace = instace
|
||||
self._baremetal = None
|
||||
|
||||
def baremetal(self):
|
||||
|
||||
if self._baremetal is None:
|
||||
|
||||
endpoint = self._instace.get_endpoint_for_service_type(
|
||||
"baremetal",
|
||||
region_name=self._instace._region_name,
|
||||
)
|
||||
|
||||
token = self._instace.auth.get_token(self._instace.session)
|
||||
|
||||
self._baremetal = ironic_client.get_client(
|
||||
1, os_auth_token=token, ironic_url=endpoint)
|
||||
|
||||
return self._baremetal
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import mock
|
||||
from openstackclient.tests import utils
|
||||
|
||||
|
||||
class FakeClientWrapper(object):
|
||||
|
||||
def __init__(self):
|
||||
self._instace = mock.Mock()
|
||||
self._baremetal = None
|
||||
|
||||
def baremetal(self):
|
||||
|
||||
if self._baremetal is None:
|
||||
self._baremetal = mock.Mock()
|
||||
|
||||
return self._baremetal
|
||||
|
||||
|
||||
class TestBaremetal(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestBaremetal, self).setUp()
|
||||
|
||||
self.app.client_manager.rdomanager_oscplugin = FakeClientWrapper()
|
|
@ -0,0 +1,142 @@
|
|||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import tempfile
|
||||
|
||||
import json
|
||||
import mock
|
||||
import os
|
||||
|
||||
from rdomanager_oscplugin.tests.v1.baremetal import fakes
|
||||
from rdomanager_oscplugin.v1 import baremetal
|
||||
|
||||
|
||||
class TestBaremetalBase(fakes.TestBaremetal):
|
||||
|
||||
def setUp(self):
|
||||
super(TestBaremetalBase, self).setUp()
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal.ImportPlugin(self.app, None)
|
||||
|
||||
|
||||
class TestImport(TestBaremetalBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestImport, self).setUp()
|
||||
|
||||
self.json_file = tempfile.NamedTemporaryFile(mode='w', delete=False)
|
||||
self.csv_file = tempfile.NamedTemporaryFile(mode='w', delete=False)
|
||||
|
||||
self.csv_file.write("""\
|
||||
pxe_ssh,192.168.122.1,root,"KEY1",00:d0:28:4c:e8:e8
|
||||
pxe_ssh,192.168.122.1,root,"KEY2",00:7c:ef:3d:eb:60""")
|
||||
|
||||
json.dump([{
|
||||
"pm_user": "stack",
|
||||
"pm_addr": "192.168.122.1",
|
||||
"pm_password": "KEY1",
|
||||
"pm_type": "pxe_ssh",
|
||||
"mac": [
|
||||
"00:0b:d0:69:7e:59"
|
||||
],
|
||||
}, {
|
||||
"arch": "x86_64",
|
||||
"pm_user": "stack",
|
||||
"pm_addr": "192.168.122.2",
|
||||
"pm_password": "KEY2",
|
||||
"pm_type": "pxe_ssh",
|
||||
"mac": [
|
||||
"00:0b:d0:69:7e:58"
|
||||
]
|
||||
}], self.json_file)
|
||||
|
||||
self.json_file.close()
|
||||
self.csv_file.close()
|
||||
|
||||
def tearDown(self):
|
||||
|
||||
super(TestImport, self).tearDown()
|
||||
os.unlink(self.json_file.name)
|
||||
os.unlink(self.csv_file.name)
|
||||
|
||||
@mock.patch('os_cloud_config.nodes.register_all_nodes')
|
||||
def test_json_import(self, mock_register_nodes):
|
||||
|
||||
arglist = [self.json_file.name, '--json', '-s', 'http://localhost']
|
||||
|
||||
verifylist = [
|
||||
('csv', False),
|
||||
('json', True),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost',
|
||||
[
|
||||
{
|
||||
'pm_password': 'KEY1',
|
||||
'pm_type': 'pxe_ssh',
|
||||
'pm_user': 'stack',
|
||||
'pm_addr': '192.168.122.1',
|
||||
'mac': ['00:0b:d0:69:7e:59']
|
||||
}, {
|
||||
'pm_user': 'stack',
|
||||
'pm_password': 'KEY2',
|
||||
'pm_addr': '192.168.122.2',
|
||||
'arch': 'x86_64',
|
||||
'pm_type': 'pxe_ssh',
|
||||
'mac': ['00:0b:d0:69:7e:58']
|
||||
}
|
||||
],
|
||||
client=self.app.client_manager.rdomanager_oscplugin.baremetal(),
|
||||
keystone_client=None)
|
||||
|
||||
@mock.patch('os_cloud_config.nodes.register_all_nodes')
|
||||
def test_csv_import(self, mock_register_nodes):
|
||||
|
||||
arglist = [self.csv_file.name, '--csv', '-s', 'http://localhost']
|
||||
|
||||
verifylist = [
|
||||
('csv', True),
|
||||
('json', False),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_register_nodes.assert_called_with(
|
||||
'http://localhost',
|
||||
[
|
||||
{
|
||||
'pm_password': 'KEY1',
|
||||
'pm_user': 'root',
|
||||
'pm_type': 'pxe_ssh',
|
||||
'pm_addr': '192.168.122.1',
|
||||
'mac': ['00:d0:28:4c:e8:e8']
|
||||
}, {
|
||||
'pm_password': 'KEY2',
|
||||
'pm_user': 'root',
|
||||
'pm_type': 'pxe_ssh',
|
||||
'pm_addr': '192.168.122.1',
|
||||
'mac': ['00:7c:ef:3d:eb:60']
|
||||
}
|
||||
],
|
||||
client=self.app.client_manager.rdomanager_oscplugin.baremetal(),
|
||||
keystone_client=None)
|
|
@ -0,0 +1,89 @@
|
|||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from os_cloud_config import nodes
|
||||
|
||||
from cliff import command
|
||||
|
||||
|
||||
def _csv_to_nodes_dict(nodes_csv):
|
||||
"""Convert CSV to a list of dicts formatted for os_cloud_config
|
||||
|
||||
Given a CSV file in the format below, convert it into the
|
||||
structure expected by os_could_config JSON files.
|
||||
|
||||
pm_type, pm_addr, pm_user, pm_password, mac
|
||||
"""
|
||||
|
||||
data = []
|
||||
|
||||
for row in csv.reader(nodes_csv):
|
||||
node = {
|
||||
"pm_user": row[2],
|
||||
"pm_addr": row[1],
|
||||
"pm_password": row[3],
|
||||
"pm_type": row[0],
|
||||
"mac": [
|
||||
row[4]
|
||||
]
|
||||
}
|
||||
data.append(node)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class ImportPlugin(command.Command):
|
||||
"""Baremetal Import plugin"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ImportPlugin")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ImportPlugin, self).get_parser(prog_name)
|
||||
parser.add_argument('-s', '--service-host', dest='service_host',
|
||||
help='Nova compute service host to register nodes '
|
||||
'with')
|
||||
parser.add_argument('--json', dest='json', action='store_true')
|
||||
parser.add_argument('--csv', dest='csv', action='store_true')
|
||||
parser.add_argument('file_in', type=argparse.FileType('r'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
|
||||
# We need JSON or CSV to be specified, not both.
|
||||
if parsed_args.json == parsed_args.csv:
|
||||
print("ERROR: Either --json or --csv needs to be specified.",
|
||||
file=sys.stderr)
|
||||
return
|
||||
|
||||
if parsed_args.json is True:
|
||||
nodes_json = json.load(parsed_args.file_in)
|
||||
else:
|
||||
nodes_json = _csv_to_nodes_dict(parsed_args.file_in)
|
||||
|
||||
nodes.register_all_nodes(
|
||||
parsed_args.service_host,
|
||||
nodes_json,
|
||||
client=self.app.client_manager.rdomanager_oscplugin.baremetal(),
|
||||
keystone_client=self.app.client_manager.identity)
|
|
@ -4,7 +4,9 @@
|
|||
pbr>=0.6,!=0.7,<1.0
|
||||
|
||||
Babel>=1.3
|
||||
cliff>=1.7.0 # Apache-2.0
|
||||
cliff-tablib>=1.0
|
||||
cliff>=1.7.0 # Apache-2.0
|
||||
os-cloud-config
|
||||
python-ironicclient>=0.4.1
|
||||
python-openstackclient>=1.0.0
|
||||
|
||||
|
|
|
@ -51,9 +51,10 @@ output_file = rdomanager_oscplugin/locale/rdomanager-oscplugin.pot
|
|||
|
||||
[entry_points]
|
||||
openstack.cli.extension =
|
||||
rdomanger_oscplugin = rdomanager_oscplugin.plugin
|
||||
rdomanager_oscplugin = rdomanager_oscplugin.plugin
|
||||
|
||||
openstack.rdomanager_oscplugin.v1 =
|
||||
undercloud_install = rdomanager_oscplugin.v1.undercloud:InstallPlugin
|
||||
baremetal_import = rdomanager_oscplugin.v1.baremetal:ImportPlugin
|
||||
overcloud_image_build = rdomanager_oscplugin.v1.overcloud_image:BuildPlugin
|
||||
overcloud_image_create = rdomanager_oscplugin.v1.overcloud_image:CreatePlugin
|
||||
undercloud_install = rdomanager_oscplugin.v1.undercloud:InstallPlugin
|
||||
|
|
Loading…
Reference in New Issue