1"""
2Neutron module for interacting with OpenStack Neutron
3
4.. versionadded:: 2018.3.0
5
6:depends:shade
7
8Example configuration
9
10.. code-block:: yaml
11
12    neutron:
13      cloud: default
14
15.. code-block:: yaml
16
17    neutron:
18      auth:
19        username: admin
20        password: password123
21        user_domain_name: mydomain
22        project_name: myproject
23        project_domain_name: myproject
24        auth_url: https://example.org:5000/v3
25      identity_api_version: 3
26"""
27
28
29HAS_SHADE = False
30try:
31    import shade
32
33    HAS_SHADE = True
34except ImportError:
35    pass
36
37__virtualname__ = "neutronng"
38
39
40def __virtual__():
41    """
42    Only load this module if shade python module is installed
43    """
44    if HAS_SHADE:
45        return __virtualname__
46    return (
47        False,
48        "The neutronng execution module failed to load: shade python module is not available",
49    )
50
51
52def compare_changes(obj, **kwargs):
53    """
54    Compare two dicts returning only keys that exist in the first dict and are
55    different in the second one
56    """
57    changes = {}
58    for key, value in obj.items():
59        if key in kwargs:
60            if value != kwargs[key]:
61                changes[key] = kwargs[key]
62    return changes
63
64
65def _clean_kwargs(keep_name=False, **kwargs):
66    """
67    Sanatize the arguments for use with shade
68    """
69    if "name" in kwargs and not keep_name:
70        kwargs["name_or_id"] = kwargs.pop("name")
71
72    return __utils__["args.clean_kwargs"](**kwargs)
73
74
75def setup_clouds(auth=None):
76    """
77    Call functions to create Shade cloud objects in __context__ to take
78    advantage of Shade's in-memory caching across several states
79    """
80    get_operator_cloud(auth)
81    get_openstack_cloud(auth)
82
83
84def get_operator_cloud(auth=None):
85    """
86    Return an operator_cloud
87    """
88    if auth is None:
89        auth = __salt__["config.option"]("neutron", {})
90    if "shade_opcloud" in __context__:
91        if __context__["shade_opcloud"].auth == auth:
92            return __context__["shade_opcloud"]
93    __context__["shade_opcloud"] = shade.operator_cloud(**auth)
94    return __context__["shade_opcloud"]
95
96
97def get_openstack_cloud(auth=None):
98    """
99    Return an openstack_cloud
100    """
101    if auth is None:
102        auth = __salt__["config.option"]("neutron", {})
103    if "shade_oscloud" in __context__:
104        if __context__["shade_oscloud"].auth == auth:
105            return __context__["shade_oscloud"]
106    __context__["shade_oscloud"] = shade.openstack_cloud(**auth)
107    return __context__["shade_oscloud"]
108
109
110def network_create(auth=None, **kwargs):
111    """
112    Create a network
113
114    name
115        Name of the network being created
116
117    shared : False
118        If ``True``, set the network as shared
119
120    admin_state_up : True
121        If ``True``, Set the network administrative state to "up"
122
123    external : False
124        Control whether or not this network is externally accessible
125
126    provider
127        An optional Python dictionary of network provider options
128
129    project_id
130        The project ID on which this network will be created
131
132    CLI Example:
133
134    .. code-block:: bash
135
136        salt '*' neutronng.network_create name=network2 \
137          shared=True admin_state_up=True external=True
138
139        salt '*' neutronng.network_create name=network3 \
140          provider='{"network_type": "vlan",\
141                     "segmentation_id": "4010",\
142                     "physical_network": "provider"}' \
143          project_id=1dcac318a83b4610b7a7f7ba01465548
144
145    """
146    cloud = get_operator_cloud(auth)
147    kwargs = _clean_kwargs(keep_name=True, **kwargs)
148    return cloud.create_network(**kwargs)
149
150
151def network_delete(auth=None, **kwargs):
152    """
153    Delete a network
154
155    name_or_id
156        Name or ID of the network being deleted
157
158    CLI Example:
159
160    .. code-block:: bash
161
162        salt '*' neutronng.network_delete name_or_id=network1
163        salt '*' neutronng.network_delete name_or_id=1dcac318a83b4610b7a7f7ba01465548
164
165    """
166    cloud = get_operator_cloud(auth)
167    kwargs = _clean_kwargs(**kwargs)
168    return cloud.delete_network(**kwargs)
169
170
171def list_networks(auth=None, **kwargs):
172    """
173    List networks
174
175    filters
176        A Python dictionary of filter conditions to push down
177
178    CLI Example:
179
180    .. code-block:: bash
181
182        salt '*' neutronng.list_networks
183        salt '*' neutronng.list_networks \
184          filters='{"tenant_id": "1dcac318a83b4610b7a7f7ba01465548"}'
185
186    """
187    cloud = get_operator_cloud(auth)
188    kwargs = _clean_kwargs(**kwargs)
189    return cloud.list_networks(**kwargs)
190
191
192def network_get(auth=None, **kwargs):
193    """
194    Get a single network
195
196    filters
197        A Python dictionary of filter conditions to push down
198
199    CLI Example:
200
201    .. code-block:: bash
202
203        salt '*' neutronng.network_get name=XLB4
204
205    """
206    cloud = get_operator_cloud(auth)
207    kwargs = _clean_kwargs(**kwargs)
208    return cloud.get_network(**kwargs)
209
210
211def subnet_create(auth=None, **kwargs):
212    """
213    Create a subnet
214
215    network_name_or_id
216        The unique name or ID of the attached network. If a non-unique name is
217        supplied, an exception is raised.
218
219    cidr
220        The CIDR
221
222    ip_version
223        The IP version, which is 4 or 6.
224
225    enable_dhcp : False
226        Set to ``True`` if DHCP is enabled and ``False`` if disabled
227
228    subnet_name
229        The name of the subnet
230
231    tenant_id
232        The ID of the tenant who owns the network. Only administrative users
233        can specify a tenant ID other than their own.
234
235    allocation_pools
236        A list of dictionaries of the start and end addresses for the
237        allocation pools.
238
239    gateway_ip
240        The gateway IP address. When you specify both ``allocation_pools`` and
241        ``gateway_ip``, you must ensure that the gateway IP does not overlap
242        with the specified allocation pools.
243
244    disable_gateway_ip : False
245        Set to ``True`` if gateway IP address is disabled and ``False`` if
246        enabled. It is not allowed with ``gateway_ip``.
247
248    dns_nameservers
249        A list of DNS name servers for the subnet
250
251    host_routes
252        A list of host route dictionaries for the subnet
253
254    ipv6_ra_mode
255        IPv6 Router Advertisement mode. Valid values are ``dhcpv6-stateful``,
256        ``dhcpv6-stateless``, or ``slaac``.
257
258    ipv6_address_mode
259        IPv6 address mode. Valid values are ``dhcpv6-stateful``,
260        ``dhcpv6-stateless``, or ``slaac``.
261
262    use_default_subnetpool
263        If ``True``, use the default subnetpool for ``ip_version`` to obtain a
264        CIDR. It is required to pass ``None`` to the ``cidr`` argument when
265        enabling this option.
266
267    CLI Example:
268
269    .. code-block:: bash
270
271        salt '*' neutronng.subnet_create network_name_or_id=network1
272          subnet_name=subnet1
273
274        salt '*' neutronng.subnet_create subnet_name=subnet2\
275          network_name_or_id=network2 enable_dhcp=True \
276          allocation_pools='[{"start": "192.168.199.2",\
277                              "end": "192.168.199.254"}]'\
278          gateway_ip='192.168.199.1' cidr=192.168.199.0/24
279
280        salt '*' neutronng.subnet_create network_name_or_id=network1 \
281          subnet_name=subnet1 dns_nameservers='["8.8.8.8", "8.8.8.7"]'
282
283    """
284    cloud = get_operator_cloud(auth)
285    kwargs = _clean_kwargs(**kwargs)
286    return cloud.create_subnet(**kwargs)
287
288
289def subnet_update(auth=None, **kwargs):
290    """
291    Update a subnet
292
293    name_or_id
294        Name or ID of the subnet to update
295
296    subnet_name
297        The new name of the subnet
298
299    enable_dhcp
300        Set to ``True`` if DHCP is enabled and ``False`` if disabled
301
302    gateway_ip
303        The gateway IP address. When you specify both allocation_pools and
304        gateway_ip, you must ensure that the gateway IP does not overlap with
305        the specified allocation pools.
306
307    disable_gateway_ip : False
308        Set to ``True`` if gateway IP address is disabled and False if enabled.
309        It is not allowed with ``gateway_ip``.
310
311    allocation_pools
312        A list of dictionaries of the start and end addresses for the
313        allocation pools.
314
315    dns_nameservers
316        A list of DNS name servers for the subnet
317
318    host_routes
319        A list of host route dictionaries for the subnet
320
321    .. code-block:: bash
322
323        salt '*' neutronng.subnet_update name=subnet1 subnet_name=subnet2
324        salt '*' neutronng.subnet_update name=subnet1 dns_nameservers='["8.8.8.8", "8.8.8.7"]'
325
326    """
327    cloud = get_operator_cloud(auth)
328    kwargs = _clean_kwargs(**kwargs)
329    return cloud.update_subnet(**kwargs)
330
331
332def subnet_delete(auth=None, **kwargs):
333    """
334    Delete a subnet
335
336    name
337        Name or ID of the subnet to update
338
339    CLI Example:
340
341    .. code-block:: bash
342
343        salt '*' neutronng.subnet_delete name=subnet1
344        salt '*' neutronng.subnet_delete \
345          name=1dcac318a83b4610b7a7f7ba01465548
346
347    """
348    cloud = get_operator_cloud(auth)
349    kwargs = _clean_kwargs(**kwargs)
350    return cloud.delete_subnet(**kwargs)
351
352
353def list_subnets(auth=None, **kwargs):
354    """
355    List subnets
356
357    filters
358        A Python dictionary of filter conditions to push down
359
360    CLI Example:
361
362    .. code-block:: bash
363
364        salt '*' neutronng.list_subnets
365        salt '*' neutronng.list_subnets \
366          filters='{"tenant_id": "1dcac318a83b4610b7a7f7ba01465548"}'
367
368    """
369    cloud = get_operator_cloud(auth)
370    kwargs = _clean_kwargs(**kwargs)
371    return cloud.list_subnets(**kwargs)
372
373
374def subnet_get(auth=None, **kwargs):
375    """
376    Get a single subnet
377
378    filters
379        A Python dictionary of filter conditions to push down
380
381    CLI Example:
382
383    .. code-block:: bash
384
385        salt '*' neutronng.subnet_get name=subnet1
386
387    """
388    cloud = get_operator_cloud(auth)
389    kwargs = _clean_kwargs(**kwargs)
390    return cloud.get_subnet(**kwargs)
391
392
393def security_group_create(auth=None, **kwargs):
394    """
395    Create a security group. Use security_group_get to create default.
396
397    project_id
398        The project ID on which this security group will be created
399
400    CLI Example:
401
402    .. code-block:: bash
403
404        salt '*' neutronng.security_group_create name=secgroup1 \
405          description="Very secure security group"
406        salt '*' neutronng.security_group_create name=secgroup1 \
407          description="Very secure security group" \
408          project_id=1dcac318a83b4610b7a7f7ba01465548
409
410    """
411    cloud = get_operator_cloud(auth)
412    kwargs = _clean_kwargs(keep_name=True, **kwargs)
413    return cloud.create_security_group(**kwargs)
414
415
416def security_group_update(secgroup=None, auth=None, **kwargs):
417    """
418    Update a security group
419
420    secgroup
421        Name, ID or Raw Object of the security group to update
422
423    name
424        New name for the security group
425
426    description
427        New description for the security group
428
429    CLI Example:
430
431    .. code-block:: bash
432
433        salt '*' neutronng.security_group_update secgroup=secgroup1 \
434          description="Very secure security group"
435        salt '*' neutronng.security_group_update secgroup=secgroup1 \
436          description="Very secure security group" \
437          project_id=1dcac318a83b4610b7a7f7ba01465548
438
439    """
440    cloud = get_operator_cloud(auth)
441    kwargs = _clean_kwargs(keep_name=True, **kwargs)
442    return cloud.update_security_group(secgroup, **kwargs)
443
444
445def security_group_delete(auth=None, **kwargs):
446    """
447    Delete a security group
448
449    name_or_id
450        The name or unique ID of the security group
451
452    CLI Example:
453
454    .. code-block:: bash
455
456        salt '*' neutronng.security_group_delete name_or_id=secgroup1
457
458    """
459    cloud = get_operator_cloud(auth)
460    kwargs = _clean_kwargs(**kwargs)
461    return cloud.delete_security_group(**kwargs)
462
463
464def security_group_get(auth=None, **kwargs):
465    """
466    Get a single security group. This will create a default security group
467    if one does not exist yet for a particular project id.
468
469    filters
470        A Python dictionary of filter conditions to push down
471
472    CLI Example:
473
474    .. code-block:: bash
475
476        salt '*' neutronng.security_group_get \
477          name=1dcac318a83b4610b7a7f7ba01465548
478
479        salt '*' neutronng.security_group_get \
480          name=default\
481          filters='{"tenant_id":"2e778bb64ca64a199eb526b5958d8710"}'
482    """
483    cloud = get_operator_cloud(auth)
484    kwargs = _clean_kwargs(**kwargs)
485    return cloud.get_security_group(**kwargs)
486
487
488def security_group_rule_create(auth=None, **kwargs):
489    """
490    Create a rule in a security group
491
492    secgroup_name_or_id
493        The security group name or ID to associate with this security group
494        rule. If a non-unique group name is given, an exception is raised.
495
496    port_range_min
497        The minimum port number in the range that is matched by the security
498        group rule. If the protocol is TCP or UDP, this value must be less than
499        or equal to the port_range_max attribute value. If nova is used by the
500        cloud provider for security groups, then a value of None will be
501        transformed to -1.
502
503    port_range_max
504        The maximum port number in the range that is matched by the security
505        group rule. The port_range_min attribute constrains the port_range_max
506        attribute. If nova is used by the cloud provider for security groups,
507        then a value of None will be transformed to -1.
508
509    protocol
510        The protocol that is matched by the security group rule.  Valid values
511        are ``None``, ``tcp``, ``udp``, and ``icmp``.
512
513    remote_ip_prefix
514        The remote IP prefix to be associated with this security group rule.
515        This attribute matches the specified IP prefix as the source IP address
516        of the IP packet.
517
518    remote_group_id
519        The remote group ID to be associated with this security group rule
520
521    direction
522        Either ``ingress`` or ``egress``; the direction in which the security
523        group rule is applied. For a compute instance, an ingress security
524        group rule is applied to incoming (ingress) traffic for that instance.
525        An egress rule is applied to traffic leaving the instance
526
527    ethertype
528        Must be IPv4 or IPv6, and addresses represented in CIDR must match the
529        ingress or egress rules
530
531    project_id
532        Specify the project ID this security group will be created on
533        (admin-only)
534
535    CLI Example:
536
537    .. code-block:: bash
538
539        salt '*' neutronng.security_group_rule_create\
540          secgroup_name_or_id=secgroup1
541
542        salt '*' neutronng.security_group_rule_create\
543          secgroup_name_or_id=secgroup2 port_range_min=8080\
544          port_range_max=8080 direction='egress'
545
546        salt '*' neutronng.security_group_rule_create\
547          secgroup_name_or_id=c0e1d1ce-7296-405e-919d-1c08217be529\
548          protocol=icmp project_id=1dcac318a83b4610b7a7f7ba01465548
549
550    """
551    cloud = get_operator_cloud(auth)
552    kwargs = _clean_kwargs(**kwargs)
553    return cloud.create_security_group_rule(**kwargs)
554
555
556def security_group_rule_delete(auth=None, **kwargs):
557    """
558    Delete a security group
559
560    name_or_id
561        The unique ID of the security group rule
562
563    CLI Example:
564
565    .. code-block:: bash
566
567        salt '*' neutronng.security_group_rule_delete name_or_id=1dcac318a83b4610b7a7f7ba01465548
568
569    """
570    cloud = get_operator_cloud(auth)
571    kwargs = _clean_kwargs(**kwargs)
572    return cloud.delete_security_group_rule(**kwargs)
573