Skip to content

Commit dd803f8

Browse files
author
Yong Sheng Gong
committed
add keystone support, new command interface, API v2.0
blueprint new-cli Bug #1001053 Implement new commands interface, ready for v2.0. adopt cliff arch. new client binary is quantumv2. After it is stable, we will remove quantum binary. Httplibs2 is used. usage: https://docs.google.com/document/d/1e_4UtnhFfgtnsB8EVB31BZKldaVzl_BlsGnGBrKmcDk/edit Patch 2: add license header Patch 3: add v1.0 support, fix show net details Patch 4: quantumclient network api v2.0 Patch 5: subnet and port commands for api v2.0, add fields selector Patch 6: add test cases Patch 7: fix interactive mode, modify according to comments and https://review.openstack.org/#/c/8366/, add two tasks to BP: noauth and openstack common Patch 8: fix log problem Patch 9: modify according to the comments by dan on patch 5 Patch 10: just trigger jenkins Patch 11: pep 1.3 fix Patch 12: cliff and prettytable to more than 0.6.0 Patch 13: change setup.py to include more packages Patch 14: pep check on jenkins Patch 15: add license text to empty __init__.py files Patch 16: fix v1.1 test cases after server changes Change-Id: Ibbbdd834371c6a023b31e4797718fc0fe9786d89
1 parent f7086ed commit dd803f8

32 files changed

+3550
-114
lines changed

quantumclient/__init__.py

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,46 @@
3030

3131
from quantumclient.common import exceptions
3232
from quantumclient.common.serializer import Serializer
33-
33+
from quantumclient.common import utils
34+
35+
net_filters_v11_opt = []
36+
net_filters_v11_opt.append({'--name':
37+
{'help': _('name filter'), }, })
38+
net_filters_v11_opt.append({'--op-status':
39+
{'help': _('op-status filter'), }, })
40+
net_filters_v11_opt.append({'--port-op-status':
41+
{'help': _('port-op-status filter'), }, })
42+
net_filters_v11_opt.append({'--port-state':
43+
{'help': _('port-state filter'), }, })
44+
net_filters_v11_opt.append({'--has-attachment':
45+
{'help': _('has-attachment filter'), }, })
46+
net_filters_v11_opt.append({'--attachment':
47+
{'help': _('attachment filter'), }, })
48+
net_filters_v11_opt.append({'--port':
49+
{'help': _('port filter'), }, })
50+
51+
port_filters_v11_opt = []
52+
port_filters_v11_opt.append({'--name':
53+
{'help': _('name filter'), }, })
54+
port_filters_v11_opt.append({'--op-status':
55+
{'help': _('op-status filter'), }, })
56+
port_filters_v11_opt.append({'--has-attachment':
57+
{'help': _('has-attachment filter'), }, })
58+
port_filters_v11_opt.append({'--attachement':
59+
{'help': _('attachment filter'), }, })
60+
61+
net_filters_v11 = []
62+
for arg in net_filters_v11_opt:
63+
for key in arg.iterkeys():
64+
net_filters_v11.append(key.split('--', 2)[1])
65+
66+
port_filters_v11 = []
67+
for arg in port_filters_v11_opt:
68+
for key in arg.iterkeys():
69+
port_filters_v11.append(key.split('--', 2)[1])
3470

3571
LOG = logging.getLogger('quantumclient')
3672

37-
3873
AUTH_TOKEN_HEADER = "X-Auth-Token"
3974

4075

@@ -55,21 +90,19 @@ def exception_handler_v10(status_code, error_content):
5590
430: 'portNotFound',
5691
431: 'requestedStateInvalid',
5792
432: 'portInUse',
58-
440: 'alreadyAttached',
59-
}
93+
440: 'alreadyAttached', }
6094

6195
quantum_errors = {
6296
400: exceptions.BadInputError,
63-
401: exceptions.NotAuthorized,
97+
401: exceptions.Unauthorized,
6498
404: exceptions.NotFound,
6599
420: exceptions.NetworkNotFoundClient,
66100
421: exceptions.NetworkInUseClient,
67101
430: exceptions.PortNotFoundClient,
68102
431: exceptions.StateInvalidClient,
69103
432: exceptions.PortInUseClient,
70104
440: exceptions.AlreadyAttachedClient,
71-
501: NotImplementedError,
72-
}
105+
501: NotImplementedError, }
73106

74107
# Find real error type
75108
error_type = None
@@ -105,7 +138,7 @@ def exception_handler_v11(status_code, error_content):
105138
'RequestedStateInvalid': exceptions.StateInvalidClient,
106139
'PortInUse': exceptions.PortInUseClient,
107140
'AlreadyAttached': exceptions.AlreadyAttachedClient,
108-
}
141+
'QuantumServiceFault': exceptions.QuantumClientException, }
109142

110143
error_dict = None
111144
if isinstance(error_content, dict):
@@ -156,6 +189,33 @@ def with_params(*args, **kwargs):
156189
return with_params
157190

158191

192+
class APIFilterCall(object):
193+
194+
def __init__(self, filters):
195+
self.filters = filters
196+
197+
def __call__(self, f):
198+
def wrapped_f(*args, **kwargs):
199+
"""
200+
Temporarily sets the format and tenant for this request
201+
"""
202+
instance = args[0]
203+
(format, tenant) = (instance.format, instance.tenant)
204+
205+
if 'format' in kwargs:
206+
instance.format = kwargs['format']
207+
if 'format' not in self.filters:
208+
del kwargs['format']
209+
if 'tenant' in kwargs:
210+
instance.tenant = kwargs['tenant']
211+
if 'tenant' not in self.filters:
212+
del kwargs['tenant']
213+
ret = f(*args, **kwargs)
214+
(instance.format, instance.tenant) = (format, tenant)
215+
return ret
216+
return wrapped_f
217+
218+
159219
class Client(object):
160220

161221
"""A base client class - derived from Glance.BaseClient"""
@@ -166,13 +226,10 @@ class Client(object):
166226
"attributes": {
167227
"network": ["id", "name"],
168228
"port": ["id", "state"],
169-
"attachment": ["id"]},
229+
"attachment": ["id"], },
170230
"plurals": {
171231
"networks": "network",
172-
"ports": "port",
173-
},
174-
},
175-
}
232+
"ports": "port", }, }, }
176233

177234
# Action query strings
178235
networks_path = "/networks"
@@ -298,19 +355,18 @@ def do_request(self, method, action, body=None,
298355
headers[AUTH_TOKEN_HEADER] = self.auth_token
299356
# Open connection and send request, handling SSL certs
300357
certs = {'key_file': self.key_file, 'cert_file': self.cert_file}
301-
certs = dict((x, certs[x]) for x in certs if certs[x] != None)
358+
certs = dict((x, certs[x]) for x in certs if certs[x] is not None)
302359
if self.use_ssl and len(certs):
303360
conn = connection_type(self.host, self.port, **certs)
304361
else:
305362
conn = connection_type(self.host, self.port)
306-
# besides HTTP(s)Connection, we still have testConnection
307-
if (LOG.isEnabledFor(logging.DEBUG) and
308-
isinstance(conn, httplib.HTTPConnection)):
309-
conn.set_debuglevel(1)
310-
311363
res = self._send_request(conn, method, action, body, headers)
312364
status_code = self.get_status_code(res)
313365
data = res.read()
366+
utils.http_log(LOG, [method, action],
367+
{'body': body,
368+
'headers': headers,
369+
}, res, data)
314370
if self.logger:
315371
self.logger.debug("Quantum Client Reply (code = %s) :\n %s" %
316372
(str(status_code), data))
@@ -531,30 +587,30 @@ class ClientV11(Client):
531587
features specific to API v1.1 such as filters
532588
"""
533589

534-
@ApiCall
590+
@APIFilterCall(net_filters_v11)
535591
def list_networks(self, **filters):
536592
"""
537593
Fetches a list of all networks for a tenant
538594
"""
539595
# Pass filters in "params" argument to do_request
540596
return self.get(self.networks_path, params=filters)
541597

542-
@ApiCall
598+
@APIFilterCall(net_filters_v11)
543599
def list_networks_details(self, **filters):
544600
"""
545601
Fetches a detailed list of all networks for a tenant
546602
"""
547603
return self.get(self.networks_path + self.detail_path, params=filters)
548604

549-
@ApiCall
605+
@APIFilterCall(port_filters_v11)
550606
def list_ports(self, network, **filters):
551607
"""
552608
Fetches a list of ports on a given network
553609
"""
554610
# Pass filters in "params" argument to do_request
555611
return self.get(self.ports_path % (network), params=filters)
556612

557-
@ApiCall
613+
@APIFilterCall(port_filters_v11)
558614
def list_ports_details(self, network, **filters):
559615
"""
560616
Fetches a detailed list of ports on a given network

quantumclient/cli.py

Lines changed: 25 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
from quantumclient import ClientV11
3030
from quantumclient.common import exceptions
3131
from quantumclient.common import utils
32-
32+
from quantumclient import net_filters_v11
33+
from quantumclient import port_filters_v11
3334

3435
# Configure logger for client - cli logger is a child of it
3536
# NOTE(salvatore-orlando): logger name does not map to package
@@ -43,107 +44,80 @@
4344
commands_v10 = {
4445
"list_nets": {
4546
"func": cli_lib.list_nets,
46-
"args": ["tenant-id"],
47-
},
47+
"args": ["tenant-id"], },
4848
"list_nets_detail": {
4949
"func": cli_lib.list_nets_detail,
50-
"args": ["tenant-id"],
51-
},
50+
"args": ["tenant-id"], },
5251
"create_net": {
5352
"func": cli_lib.create_net,
54-
"args": ["tenant-id", "net-name"],
55-
},
53+
"args": ["tenant-id", "net-name"], },
5654
"delete_net": {
5755
"func": cli_lib.delete_net,
58-
"args": ["tenant-id", "net-id"],
59-
},
56+
"args": ["tenant-id", "net-id"], },
6057
"show_net": {
6158
"func": cli_lib.show_net,
62-
"args": ["tenant-id", "net-id"],
63-
},
59+
"args": ["tenant-id", "net-id"], },
6460
"show_net_detail": {
6561
"func": cli_lib.show_net_detail,
66-
"args": ["tenant-id", "net-id"],
67-
},
62+
"args": ["tenant-id", "net-id"], },
6863
"update_net": {
6964
"func": cli_lib.update_net,
70-
"args": ["tenant-id", "net-id", "new-name"],
71-
},
65+
"args": ["tenant-id", "net-id", "new-name"], },
7266
"list_ports": {
7367
"func": cli_lib.list_ports,
74-
"args": ["tenant-id", "net-id"],
75-
},
68+
"args": ["tenant-id", "net-id"], },
7669
"list_ports_detail": {
7770
"func": cli_lib.list_ports_detail,
78-
"args": ["tenant-id", "net-id"],
79-
},
71+
"args": ["tenant-id", "net-id"], },
8072
"create_port": {
8173
"func": cli_lib.create_port,
82-
"args": ["tenant-id", "net-id"],
83-
},
74+
"args": ["tenant-id", "net-id"], },
8475
"delete_port": {
8576
"func": cli_lib.delete_port,
86-
"args": ["tenant-id", "net-id", "port-id"],
87-
},
77+
"args": ["tenant-id", "net-id", "port-id"], },
8878
"update_port": {
8979
"func": cli_lib.update_port,
90-
"args": ["tenant-id", "net-id", "port-id", "params"],
91-
},
80+
"args": ["tenant-id", "net-id", "port-id", "params"], },
9281
"show_port": {
9382
"func": cli_lib.show_port,
94-
"args": ["tenant-id", "net-id", "port-id"],
95-
},
83+
"args": ["tenant-id", "net-id", "port-id"], },
9684
"show_port_detail": {
9785
"func": cli_lib.show_port_detail,
98-
"args": ["tenant-id", "net-id", "port-id"],
99-
},
86+
"args": ["tenant-id", "net-id", "port-id"], },
10087
"plug_iface": {
10188
"func": cli_lib.plug_iface,
102-
"args": ["tenant-id", "net-id", "port-id", "iface-id"],
103-
},
89+
"args": ["tenant-id", "net-id", "port-id", "iface-id"], },
10490
"unplug_iface": {
10591
"func": cli_lib.unplug_iface,
106-
"args": ["tenant-id", "net-id", "port-id"],
107-
},
92+
"args": ["tenant-id", "net-id", "port-id"], },
10893
"show_iface": {
10994
"func": cli_lib.show_iface,
110-
"args": ["tenant-id", "net-id", "port-id"],
111-
},
112-
}
95+
"args": ["tenant-id", "net-id", "port-id"], }, }
11396

11497
commands_v11 = commands_v10.copy()
11598
commands_v11.update({
11699
"list_nets": {
117100
"func": cli_lib.list_nets_v11,
118101
"args": ["tenant-id"],
119-
"filters": ["name", "op-status", "port-op-status", "port-state",
120-
"has-attachment", "attachment", "port"],
121-
},
102+
"filters": net_filters_v11, },
122103
"list_nets_detail": {
123104
"func": cli_lib.list_nets_detail_v11,
124105
"args": ["tenant-id"],
125-
"filters": ["name", "op-status", "port-op-status", "port-state",
126-
"has-attachment", "attachment", "port"],
127-
},
106+
"filters": net_filters_v11, },
128107
"list_ports": {
129108
"func": cli_lib.list_ports_v11,
130109
"args": ["tenant-id", "net-id"],
131-
"filters": ["name", "op-status", "has-attachment", "attachment"],
132-
},
110+
"filters": port_filters_v11, },
133111
"list_ports_detail": {
134112
"func": cli_lib.list_ports_detail_v11,
135113
"args": ["tenant-id", "net-id"],
136-
"filters": ["name", "op-status", "has-attachment", "attachment"],
137-
},
138-
})
114+
"filters": port_filters_v11, }, })
139115
commands = {
140116
'1.0': commands_v10,
141-
'1.1': commands_v11,
142-
}
117+
'1.1': commands_v11, }
143118
clients = {
144119
'1.0': Client,
145-
'1.1': ClientV11,
146-
}
120+
'1.1': ClientV11, }
147121

148122

149123
def help(version):

quantumclient/cli_lib.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,7 @@ class CmdOutputTemplate(OutputTemplate):
201201
plugged in Logical Port ID: %(port_id)s
202202
on Virtual Network: %(network_id)s
203203
for Tenant: %(tenant_id)s
204-
""".strip(),
205-
)
204+
""".strip(), )
206205

207206
_templates_v11 = _templates_v10.copy()
208207
_templates_v11.update(dict(
@@ -236,13 +235,11 @@ class CmdOutputTemplate(OutputTemplate):
236235
interface: %(port.attachment.id)s
237236
on Virtual Network: %(network_id)s
238237
for Tenant: %(tenant_id)s
239-
""".strip(),
240-
))
238+
""".strip(), ))
241239

242240
_templates = {
243241
'1.0': _templates_v10,
244-
'1.1': _templates_v11
245-
}
242+
'1.1': _templates_v11, }
246243

247244
def __init__(self, cmd, data, version):
248245
super(CmdOutputTemplate, self).__init__(

0 commit comments

Comments
 (0)