Merge "Implement Node commands"

This commit is contained in:
Jenkins
2013-09-26 02:42:01 +00:00
committed by Gerrit Code Review
4 changed files with 224 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
# -*- encoding: utf-8 -*-
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# 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 copy
import testtools
from ironicclient.tests import utils
import ironicclient.v1.node
NODE = {'id': 123,
'uuid': '66666666-7777-8888-9999-000000000000',
'chassis_id': 42,
'driver': 'fake',
'driver_info': {'user': 'foo', 'password': 'bar'},
'properties': {'num_cpu': 4},
'extra': {}}
CREATE_NODE = copy.deepcopy(NODE)
del CREATE_NODE['id']
del CREATE_NODE['uuid']
fixtures = {
'/v1/nodes':
{
'GET': (
{},
{"nodes": [NODE]},
),
'POST': (
{},
CREATE_NODE,
),
},
'/v1/nodes/%s' % NODE['uuid']:
{
'GET': (
{},
NODE,
),
'DELETE': (
{},
None,
),
},
}
class NodeManagerTest(testtools.TestCase):
def setUp(self):
super(NodeManagerTest, self).setUp()
self.api = utils.FakeAPI(fixtures)
self.mgr = ironicclient.v1.node.NodeManager(self.api)
def test_node_list(self):
node = self.mgr.list()
expect = [
('GET', '/v1/nodes', {}, None),
]
self.assertEqual(self.api.calls, expect)
self.assertEqual(len(node), 1)
def test_node_show(self):
node = self.mgr.get(NODE['uuid'])
expect = [
('GET', '/v1/nodes/%s' % NODE['uuid'], {}, None),
]
self.assertEqual(self.api.calls, expect)
self.assertEqual(node.uuid, NODE['uuid'])
def test_create(self):
node = self.mgr.create(**CREATE_NODE)
expect = [
('POST', '/v1/nodes', {}, CREATE_NODE),
]
self.assertEqual(self.api.calls, expect)
self.assertTrue(node)
def test_delete(self):
node = self.mgr.delete(node_id=NODE['uuid'])
expect = [
('DELETE', '/v1/nodes/%s' % NODE['uuid'], {}, None),
]
self.assertEqual(self.api.calls, expect)
self.assertTrue(node is None)

View File

@@ -15,6 +15,7 @@
from ironicclient.common import http
from ironicclient.v1 import chassis
from ironicclient.v1 import node
from ironicclient.v1 import port
@@ -32,4 +33,5 @@ class Client(http.HTTPClient):
"""Initialize a new client for the Ironic v1 API."""
super(Client, self).__init__(*args, **kwargs)
self.chassis = chassis.ChassisManager(self)
self.node = node.NodeManager(self)
self.port = port.PortManager(self)

56
ironicclient/v1/node.py Normal file
View File

@@ -0,0 +1,56 @@
# -*- encoding: utf-8 -*-
#
# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# 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 ironicclient.common import base
from ironicclient import exc
CREATION_ATTRIBUTES = ['chassis_id', 'driver', 'driver_info', 'extra',
'node_id', 'properties']
class Node(base.Resource):
def __repr__(self):
return "<Node %s>" % self._info
class NodeManager(base.Manager):
resource_class = Node
@staticmethod
def _path(id=None):
return '/v1/nodes/%s' % id if id else '/v1/nodes'
def list(self):
return self._list(self._path(), "nodes")
def get(self, node_id):
try:
return self._list(self._path(node_id))[0]
except IndexError:
return None
def create(self, **kwargs):
new = {}
for (key, value) in kwargs.items():
if key in CREATION_ATTRIBUTES:
new[key] = value
else:
raise exc.InvalidAttribute()
return self._create(self._path(), new)
def delete(self, node_id):
return self._delete(self._path(node_id))

View File

@@ -65,6 +65,71 @@ def do_chassis_delete(self, args):
raise exc.CommandError('Chassis not found: %s' % args.chassis)
@utils.arg('node', metavar='<node>', help="ID of node")
def do_node_show(self, args):
"""Show a node."""
try:
node = self.node.get(args.node)
except exc.HTTPNotFound:
raise exc.CommandError('Node not found: %s' % args.node)
else:
fields = ['uuid', 'instance_uuid', 'power_state', 'target_power_state',
'provision_state', 'target_provision_state', 'driver',
'driver_info', 'properties', 'extra',
'created_at', 'updated_at', 'reservation']
data = dict([(f, getattr(node, f, '')) for f in fields])
utils.print_dict(data, wrap=72)
def do_node_list(self, args):
"""List nodes."""
nodes = self.node.list()
field_labels = ['UUID', 'Instance UUID',
'Power State', 'Provisioning State']
fields = ['uuid', 'instance_uuid', 'power_state', 'provision_state']
utils.print_list(nodes, fields, field_labels, sortby=1)
@utils.arg('--driver',
metavar='<DRIVER>',
help='Driver used to control the node. [REQUIRED]')
@utils.arg('--driver_info',
metavar='<key=value>',
help='Key/value pairs used by the driver. '
'Can be specified multiple times.')
@utils.arg('--properties',
metavar='<key=value>',
help='Key/value pairs describing the physical characteristics '
'of the node. This is exported to Nova and used by the '
'scheduler. Can be specified multiple times.')
@utils.arg('--extra',
metavar='<key=value>',
help="Record arbitrary key/value metadata. "
"Can be specified multiple times.")
def do_node_create(self, args):
"""Create a new node."""
field_list = ['chassis_id', 'driver', 'driver_info', 'properties', 'extra']
fields = dict((k, v) for (k, v) in vars(args).items()
if k in field_list and not (v is None))
fields = utils.args_array_to_dict(fields, 'driver_info')
fields = utils.args_array_to_dict(fields, 'extra')
fields = utils.args_array_to_dict(fields, 'properties')
node = self.node.create(**fields)
field_list.append('uuid')
data = dict([(f, getattr(node, f, '')) for f in field_list])
utils.print_dict(data, wrap=72)
@utils.arg('node', metavar='<node>', help="ID of node")
def do_node_delete(self, args):
"""Delete a node."""
try:
self.node.delete(args.node)
except exc.HTTPNotFound:
raise exc.CommandError('Node not found: %s' % args.node)
@utils.arg('port', metavar='<port>', help="ID of port")
def do_port_show(self, args):
"""Show a port."""