Skip to content

Commit 2614474

Browse files
committed
Support Neutron Local IP CRUD
Add support for Neutron Local IP CRUD operations. Partial-Bug: #1930200 Depends-On: https://review.opendev.org/c/openstack/neutron/+/804523 Depends-On: https://review.opendev.org/c/openstack/openstacksdk/+/804988 Change-Id: I1095100efb27b8559412469f0a9d07fc0a3db9d5
1 parent f00dce9 commit 2614474

12 files changed

Lines changed: 1657 additions & 2 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=============================================
2+
Local IP Associations (local_ip_associations)
3+
=============================================
4+
5+
The resource lets users assign Local IPs to user Ports.
6+
This is a sub-resource of the Local IP resource.
7+
8+
Network v2
9+
10+
.. autoprogram-cliff:: openstack.network.v2
11+
:command: local ip association *
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=====================
2+
Local IPs (local_ips)
3+
=====================
4+
5+
Extension that allows users to create a virtual IP that can later be assigned
6+
to multiple ports/VMs (similar to anycast IP) and is guaranteed to only be
7+
reachable within the same physical server/node boundaries
8+
9+
Network v2
10+
11+
.. autoprogram-cliff:: openstack.network.v2
12+
:command: local ip *

lower-constraints.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ msgpack-python==0.4.0
3838
munch==2.1.0
3939
netaddr==0.7.18
4040
netifaces==0.10.4
41-
openstacksdk==0.56.0
41+
openstacksdk==0.61.0
4242
os-client-config==2.1.0
4343
os-service-types==1.7.0
4444
osc-lib==2.3.0
Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
# Copyright 2021 Huawei, Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
#
15+
16+
"""Node Local IP action implementations"""
17+
18+
import logging
19+
20+
from osc_lib.command import command
21+
from osc_lib import exceptions
22+
from osc_lib import utils
23+
24+
from openstackclient.i18n import _
25+
from openstackclient.identity import common as identity_common
26+
27+
LOG = logging.getLogger(__name__)
28+
29+
30+
def _get_columns(item):
31+
column_map = {}
32+
hidden_columns = ['location']
33+
return utils.get_osc_show_columns_for_sdk_resource(
34+
item, column_map, hidden_columns)
35+
36+
37+
def _get_attrs(client_manager, parsed_args):
38+
attrs = {}
39+
network_client = client_manager.network
40+
41+
if parsed_args.name:
42+
attrs['name'] = parsed_args.name
43+
if parsed_args.description:
44+
attrs['description'] = parsed_args.description
45+
if 'project' in parsed_args and parsed_args.project is not None:
46+
identity_client = client_manager.identity
47+
project_id = identity_common.find_project(
48+
identity_client,
49+
parsed_args.project,
50+
parsed_args.project_domain,
51+
).id
52+
attrs['project_id'] = project_id
53+
if parsed_args.network:
54+
network = network_client.find_network(parsed_args.network,
55+
ignore_missing=False)
56+
attrs['network_id'] = network.id
57+
if parsed_args.local_ip_address:
58+
attrs['local_ip_address'] = parsed_args.local_ip_address
59+
if parsed_args.local_port:
60+
port = network_client.find_port(parsed_args.local_port,
61+
ignore_missing=False)
62+
attrs['local_port_id'] = port.id
63+
if parsed_args.ip_mode:
64+
attrs['ip_mode'] = parsed_args.ip_mode
65+
return attrs
66+
67+
68+
class CreateLocalIP(command.ShowOne):
69+
_description = _("Create Local IP")
70+
71+
def get_parser(self, prog_name):
72+
parser = super().get_parser(prog_name)
73+
parser.add_argument(
74+
'--name',
75+
metavar="<name>",
76+
help=_("New local IP name")
77+
)
78+
parser.add_argument(
79+
'--description',
80+
metavar="<description>",
81+
help=_("New local IP description")
82+
)
83+
parser.add_argument(
84+
'--network',
85+
metavar='<network>',
86+
help=_("Network to allocate Local IP (name or ID)")
87+
)
88+
parser.add_argument(
89+
'--local-port',
90+
metavar='<local_port>',
91+
help=_("Port to allocate Local IP (name or ID)")
92+
)
93+
parser.add_argument(
94+
"--local-ip-address",
95+
metavar="<local_ip_address>",
96+
help=_("IP address or CIDR "),
97+
)
98+
parser.add_argument(
99+
'--ip-mode',
100+
metavar='<ip_mode>',
101+
help=_("local IP ip mode")
102+
)
103+
104+
identity_common.add_project_domain_option_to_parser(parser)
105+
106+
return parser
107+
108+
def take_action(self, parsed_args):
109+
client = self.app.client_manager.network
110+
attrs = _get_attrs(self.app.client_manager, parsed_args)
111+
112+
obj = client.create_local_ip(**attrs)
113+
display_columns, columns = _get_columns(obj)
114+
data = utils.get_item_properties(obj, columns, formatters={})
115+
116+
return (display_columns, data)
117+
118+
119+
class DeleteLocalIP(command.Command):
120+
_description = _("Delete local IP(s)")
121+
122+
def get_parser(self, prog_name):
123+
parser = super().get_parser(prog_name)
124+
parser.add_argument(
125+
'local_ip',
126+
metavar="<local-ip>",
127+
nargs='+',
128+
help=_("Local IP(s) to delete (name or ID)")
129+
)
130+
131+
return parser
132+
133+
def take_action(self, parsed_args):
134+
client = self.app.client_manager.network
135+
result = 0
136+
137+
for lip in parsed_args.local_ip:
138+
try:
139+
obj = client.find_local_ip(lip, ignore_missing=False)
140+
client.delete_local_ip(obj)
141+
except Exception as e:
142+
result += 1
143+
LOG.error(_("Failed to delete Local IP with "
144+
"name or ID '%(lip)s': %(e)s"),
145+
{'lip': lip, 'e': e})
146+
147+
if result > 0:
148+
total = len(parsed_args.local_ip)
149+
msg = (_("%(result)s of %(total)s local IPs failed "
150+
"to delete.") % {'result': result, 'total': total})
151+
raise exceptions.CommandError(msg)
152+
153+
154+
class SetLocalIP(command.Command):
155+
_description = _("Set local ip properties")
156+
157+
def get_parser(self, prog_name):
158+
parser = super().get_parser(prog_name)
159+
parser.add_argument(
160+
'local_ip',
161+
metavar="<local-ip>",
162+
help=_("Local IP to modify (name or ID)")
163+
)
164+
parser.add_argument(
165+
'--name',
166+
metavar="<name>",
167+
help=_('Set local IP name')
168+
)
169+
parser.add_argument(
170+
'--description',
171+
metavar="<description>",
172+
help=_('Set local IP description')
173+
)
174+
return parser
175+
176+
def take_action(self, parsed_args):
177+
client = self.app.client_manager.network
178+
obj = client.find_local_ip(
179+
parsed_args.local_ip,
180+
ignore_missing=False)
181+
attrs = {}
182+
if parsed_args.name is not None:
183+
attrs['name'] = parsed_args.name
184+
if parsed_args.description is not None:
185+
attrs['description'] = parsed_args.description
186+
if attrs:
187+
client.update_local_ip(obj, **attrs)
188+
189+
190+
class ListLocalIP(command.Lister):
191+
_description = _("List local IPs")
192+
193+
def get_parser(self, prog_name):
194+
parser = super().get_parser(prog_name)
195+
196+
parser.add_argument(
197+
'--name',
198+
metavar='<name>',
199+
help=_("List only local IPs of given name in output")
200+
)
201+
parser.add_argument(
202+
'--project',
203+
metavar="<project>",
204+
help=_("List Local IPs according to their project "
205+
"(name or ID)")
206+
)
207+
parser.add_argument(
208+
'--network',
209+
metavar='<network>',
210+
help=_("List Local IP(s) according to "
211+
"given network (name or ID)")
212+
)
213+
parser.add_argument(
214+
'--local-port',
215+
metavar='<local_port>',
216+
help=_("List Local IP(s) according to "
217+
"given port (name or ID)")
218+
)
219+
parser.add_argument(
220+
'--local-ip-address',
221+
metavar='<local_ip_address>',
222+
help=_("List Local IP(s) according to "
223+
"given Local IP Address")
224+
)
225+
parser.add_argument(
226+
'--ip-mode',
227+
metavar='<ip_mode>',
228+
help=_("List Local IP(s) according to "
229+
"given IP mode")
230+
)
231+
232+
identity_common.add_project_domain_option_to_parser(parser)
233+
234+
return parser
235+
236+
def take_action(self, parsed_args):
237+
client = self.app.client_manager.network
238+
columns = (
239+
'id',
240+
'name',
241+
'description',
242+
'project_id',
243+
'local_port_id',
244+
'network_id',
245+
'local_ip_address',
246+
'ip_mode',
247+
)
248+
column_headers = (
249+
'ID',
250+
'Name',
251+
'Description',
252+
'Project',
253+
'Local Port ID',
254+
'Network',
255+
'Local IP address',
256+
'IP mode',
257+
)
258+
attrs = {}
259+
if parsed_args.name:
260+
attrs['name'] = parsed_args.name
261+
if 'project' in parsed_args and parsed_args.project is not None:
262+
identity_client = self.app.client_manager.identity
263+
project_id = identity_common.find_project(
264+
identity_client,
265+
parsed_args.project,
266+
parsed_args.project_domain,
267+
).id
268+
attrs['project_id'] = project_id
269+
if parsed_args.network is not None:
270+
network = client.find_network(parsed_args.network,
271+
ignore_missing=False)
272+
attrs['network_id'] = network.id
273+
if parsed_args.local_port:
274+
port = client.find_port(parsed_args.local_port,
275+
ignore_missing=False)
276+
attrs['local_port_id'] = port.id
277+
if parsed_args.local_ip_address:
278+
attrs['local_ip_address'] = parsed_args.local_ip_address
279+
if parsed_args.ip_mode:
280+
attrs['ip_mode'] = parsed_args.ip_mode
281+
data = client.local_ips(**attrs)
282+
283+
return (column_headers,
284+
(utils.get_item_properties(s,
285+
columns,
286+
formatters={},) for s in data))
287+
288+
289+
class ShowLocalIP(command.ShowOne):
290+
_description = _("Display local IP details")
291+
292+
def get_parser(self, prog_name):
293+
parser = super().get_parser(prog_name)
294+
parser.add_argument(
295+
'local_ip',
296+
metavar="<local-ip>",
297+
help=_("Local IP to display (name or ID)")
298+
)
299+
300+
return parser
301+
302+
def take_action(self, parsed_args):
303+
client = self.app.client_manager.network
304+
obj = client.find_local_ip(
305+
parsed_args.local_ip,
306+
ignore_missing=False)
307+
display_columns, columns = _get_columns(obj)
308+
data = utils.get_item_properties(obj, columns, formatters={})
309+
310+
return (display_columns, data)

0 commit comments

Comments
 (0)