blob: 42e202b9a5fa40b5a6fe5c2d19f6af08b506956d [file] [log] [blame]
Oleksiy Petrenkocaad2032018-04-20 14:42:46 +03001import logging
2
3log = logging.getLogger(__name__)
4
5
6def __virtual__():
7 return 'neutronv2' if 'neutronv2.subnet_list' in __salt__ else False
8
9
10def _neutronv2_call(fname, *args, **kwargs):
11 return __salt__['neutronv2.{}'.format(fname)](*args, **kwargs)
12
13
14def _resource_present(resource, name, changeable_params, cloud_name, **kwargs):
15 try:
16 method_name = '{}_get_details'.format(resource)
17 exact_resource = _neutronv2_call(
Oleksiy Petrenko5bfb8bc2018-08-23 15:08:17 +030018 method_name, name, cloud_name=cloud_name
Oleksiy Petrenkocaad2032018-04-20 14:42:46 +030019 )[resource]
20 except Exception as e:
21 if 'ResourceNotFound' in repr(e):
22 try:
23 method_name = '{}_create'.format(resource)
24 resp = _neutronv2_call(
25 method_name, name=name, cloud_name=cloud_name, **kwargs
26 )
27 except Exception as e:
28 log.exception('Neutron {0} create failed with {1}'.
29 format(resource, e))
30 return _failed('create', name, resource)
31 return _succeeded('create', name, resource, resp)
32 elif 'MultipleResourcesFound' in repr(e):
33 return _failed('find', name, resource)
34 else:
35 raise
36
37 to_update = {}
38 for key in kwargs:
39 if key in changeable_params and (key not in exact_resource
40 or kwargs[key] != exact_resource[key]):
41 to_update[key] = kwargs[key]
42 try:
43 method_name = '{}_update'.format(resource)
44 resp = _neutronv2_call(
45 method_name, name=name, cloud_name=cloud_name, **to_update
46 )
47 except Exception as e:
48 log.exception('Neutron {0} update failed with {1}'.format(resource, e))
49 return _failed('update', name, resource)
50 return _succeeded('update', name, resource, resp)
51
52
53def _resource_absent(resource, name, cloud_name):
54 try:
55 method_name = '{}_get_details'.format(resource)
56 _neutronv2_call(
Oleksiy Petrenko5bfb8bc2018-08-23 15:08:17 +030057 method_name, name, cloud_name=cloud_name
Oleksiy Petrenkocaad2032018-04-20 14:42:46 +030058 )[resource]
59 except Exception as e:
60 if 'ResourceNotFound' in repr(e):
61 return _succeeded('absent', name, resource)
62 if 'MultipleResourcesFound' in repr(e):
63 return _failed('find', name, resource)
64 try:
65 method_name = '{}_delete'.format(resource)
66 _neutronv2_call(
Oleksiy Petrenko5bfb8bc2018-08-23 15:08:17 +030067 method_name, name, cloud_name=cloud_name
Oleksiy Petrenkocaad2032018-04-20 14:42:46 +030068 )
69 except Exception as e:
70 log.error('Neutron delete {0} failed with {1}'.format(resource, e))
71 return _failed('delete', name, resource)
72 return _succeeded('delete', name, resource)
73
74
75def network_present(name, cloud_name, **kwargs):
76 changeable = (
77 'admin_state_up', 'dns_domain', 'mtu', 'port_security_enabled',
78 'provider:network_type', 'provider:physical_network',
79 'provider:segmentation_id', 'qos_policy_id', 'router:external',
80 'segments', 'shared', 'description', 'is_default'
81 )
82
83 return _resource_present('network', name, changeable, cloud_name, **kwargs)
84
85
86def network_absent(name, cloud_name):
87 return _resource_absent('network', name, cloud_name)
88
89
90def subnet_present(name, cloud_name, network_id, ip_version, cidr, **kwargs):
91 kwargs.update({'network_id': network_id,
92 'ip_version': ip_version,
93 'cidr': cidr})
94 changeable = (
95 'name', 'enable_dhcp', 'dns_nameservers', 'allocation_pools',
96 'host_routes', 'gateway_ip', 'description', 'service_types',
97 )
98
99 return _resource_present('subnet', name, changeable, cloud_name, **kwargs)
100
101
102def subnet_absent(name, cloud_name):
103 return _resource_absent('subnet', name, cloud_name)
104
105
106def subnetpool_present(name, cloud_name, prefixes, **kwargs):
107 kwargs.update({'prefixes': prefixes})
108 changeable = (
109 'default_quota', 'min_prefixlen', 'address_scope_id',
110 'default_prefixlen', 'description'
111 )
112
113 return _resource_present('subnetpool', name, changeable, cloud_name, **kwargs)
114
115
116def subnetpool_absent(name, cloud_name):
117 return _resource_absent('subnetpool', name, cloud_name)
118
119
Oleksiy Petrenko5bfb8bc2018-08-23 15:08:17 +0300120def agent_present(name, agent_type, cloud_name, **kwargs):
121 """
122 :param name: agent host name
123 :param agent_type: type of the agent. i.e. 'L3 agent' or 'DHCP agent'
124 :param kwargs:
125 :param description: agent description
126 :param admin_state_up: administrative state of the agent
127 """
128 agents = _neutronv2_call(
129 'agent_list', host=name, agent_type=agent_type,
130 cloud_name=cloud_name)['agents']
131 # Make sure we have one and only one such agent
132 if len(agents) == 1:
133 agent = agents[0]
134 to_update = {}
135 for key in kwargs:
136 if kwargs[key] != agent[key]:
137 to_update[key] = kwargs[key]
138 if to_update:
139 try:
140 _neutronv2_call('agent_update', agent_id=agent['id'],
141 cloud_name=cloud_name, **kwargs)
142 except Exception:
143 return _failed('update', name, 'agent')
144 return _succeeded('update', name, 'agent')
145 return _succeeded('no_changes', name, 'agent')
146 else:
147 return _failed('find', name, 'agent')
148
149
Oleksiy Petrenkocaad2032018-04-20 14:42:46 +0300150def _succeeded(op, name, resource, changes=None):
151 msg_map = {
152 'create': '{0} {1} created',
153 'delete': '{0} {1} removed',
154 'update': '{0} {1} updated',
155 'no_changes': '{0} {1} is in desired state',
156 'absent': '{0} {1} not present'
157 }
158 changes_dict = {
159 'name': name,
160 'result': True,
161 'comment': msg_map[op].format(resource, name),
162 'changes': changes or {},
163 }
164 return changes_dict
165
166
167def _failed(op, name, resource):
168 msg_map = {
169 'create': '{0} {1} failed to create',
170 'delete': '{0} {1} failed to delete',
171 'update': '{0} {1} failed to update',
172 'find': '{0} {1} found multiple {0}'
173 }
174 changes_dict = {
175 'name': name,
176 'result': False,
177 'comment': msg_map[op].format(resource, name),
178 'changes': {},
179 }
180 return changes_dict