Merge "Add missing licences in requirements.txt"
[snaps.git] / snaps / openstack / create_router.py
1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 import logging
16
17 from neutronclient.common.exceptions import NotFound, Unauthorized
18
19 from snaps.config.router import RouterConfig
20 from snaps.openstack.openstack_creator import OpenStackNetworkObject
21 from snaps.openstack.utils import neutron_utils
22
23 __author__ = 'spisarski'
24
25 logger = logging.getLogger('OpenStackNetwork')
26
27
28 class OpenStackRouter(OpenStackNetworkObject):
29     """
30     Class responsible for managing a router in OpenStack
31     """
32
33     def __init__(self, os_creds, router_settings):
34         """
35         Constructor - all parameters are required
36         :param os_creds: The credentials to connect with OpenStack
37         :param router_settings: The settings used to create a router object
38                                 (must be an instance of the RouterConfig
39                                 class)
40         """
41         super(self.__class__, self).__init__(os_creds)
42
43         if not router_settings:
44             raise RouterCreationError('router_settings is required')
45
46         self.router_settings = router_settings
47
48         # Attributes instantiated on create()
49         self.__router = None
50         self.__internal_subnets = list()
51         self.__internal_router_interface = None
52
53         # Dict where the port object is the key and any newly created router
54         # interfaces are the value
55         self.__ports = list()
56
57     def initialize(self):
58         """
59         Loads the existing router.
60         :return: the Router domain object
61         """
62         super(self.__class__, self).initialize()
63
64         try:
65             self.__router = neutron_utils.get_router(
66                 self._neutron, self._keystone,
67                 router_settings=self.router_settings,
68                 project_name=self._os_creds.project_name)
69         except Unauthorized as e:
70             logger.warn('Unable to lookup router with name %s - %s',
71                         self.router_settings.name, e)
72
73         if self.__router:
74             for sub_config in self.router_settings.internal_subnets:
75                 internal_subnet = self.__get_internal_subnet(sub_config)
76                 if internal_subnet:
77                     self.__internal_subnets.append(internal_subnet)
78                 else:
79                     raise RouterCreationError(
80                         'Subnet not found with name ' + internal_subnet.name)
81
82             for port_setting in self.router_settings.port_settings:
83                 port = neutron_utils.get_port(
84                     self._neutron, self._keystone, port_settings=port_setting,
85                     project_name=self._os_creds.project_name)
86                 if port:
87                     self.__ports.append(port)
88
89         return self.__router
90
91     def create(self):
92         """
93         Responsible for creating the router.
94         :return: the Router domain object
95         """
96         self.initialize()
97
98         if not self.__router:
99             self.__router = neutron_utils.create_router(
100                 self._neutron, self._os_creds, self.router_settings)
101
102             for sub_config in self.router_settings.internal_subnets:
103                 internal_subnet = self.__get_internal_subnet(sub_config)
104                 if internal_subnet:
105                     self.__internal_subnets.append(internal_subnet)
106                     if internal_subnet:
107                         logger.debug('Adding router to subnet...')
108                         router_intf = neutron_utils.add_interface_router(
109                             self._neutron, self.__router,
110                             subnet=internal_subnet)
111                         self.__internal_router_interface = router_intf
112                 else:
113                     raise RouterCreationError(
114                         'Subnet not found with name {}'.format(sub_config))
115
116             for port_setting in self.router_settings.port_settings:
117                 port = neutron_utils.get_port(
118                     self._neutron, self._keystone, port_settings=port_setting,
119                     project_name=self._os_creds.project_name)
120                 logger.info(
121                     'Retrieved port %s for router - %s', port_setting.name,
122                     self.router_settings.name)
123                 if port:
124                     self.__ports.append(port)
125
126                 if not port:
127                     port = neutron_utils.create_port(
128                         self._neutron, self._os_creds, port_setting)
129                     if port:
130                         logger.info(
131                             'Created port %s for router - %s',
132                             port_setting.name,
133                             self.router_settings.name)
134                         self.__ports.append(port)
135                         neutron_utils.add_interface_router(
136                             self._neutron, self.__router, port=port)
137                     else:
138                         raise RouterCreationError(
139                             'Error creating port with name - '
140                             + port_setting.name)
141
142         self.__router = neutron_utils.get_router_by_id(
143             self._neutron, self.__router.id)
144         return self.__router
145
146     def __get_internal_subnet(self, sub_config):
147         """
148         returns the Subnet domain object from the subnet configurator
149         :param sub_config:
150         :return:
151         """
152         if isinstance(sub_config, dict):
153             sub_dict = sub_config['subnet']
154             network = neutron_utils.get_network(
155                 self._neutron, self._keystone,
156                 network_name=sub_dict['network_name'],
157                 project_name=sub_dict['project_name'])
158             if network:
159                 return neutron_utils.get_subnet(
160                     self._neutron, network,
161                     subnet_name=sub_dict['subnet_name'])
162         else:
163             return neutron_utils.get_subnet_by_name(
164                 self._neutron, self._keystone,
165                 subnet_name=sub_config,
166                 project_name=self._os_creds.project_name)
167
168     def clean(self):
169         """
170         Removes and deletes all items created in reverse order.
171         """
172         for port in self.__ports:
173             logger.info(
174                 'Removing router interface from router %s and port %s',
175                 self.router_settings.name, port.name)
176             try:
177                 neutron_utils.remove_interface_router(self._neutron,
178                                                       self.__router, port=port)
179             except NotFound:
180                 pass
181         self.__ports = list()
182
183         for internal_subnet in self.__internal_subnets:
184             logger.info(
185                 'Removing router interface from router %s and subnet %s',
186                 self.router_settings.name, internal_subnet.name)
187             try:
188                 neutron_utils.remove_interface_router(self._neutron,
189                                                       self.__router,
190                                                       subnet=internal_subnet)
191             except NotFound:
192                 pass
193         self.__internal_subnets = list()
194
195         if self.__router:
196             logger.info('Removing router ' + self.router_settings.name)
197             try:
198                 neutron_utils.delete_router(self._neutron, self.__router)
199             except NotFound:
200                 pass
201             self.__router = None
202
203         super(self.__class__, self).clean()
204
205     def get_router(self):
206         """
207         Returns the OpenStack router object
208         :return:
209         """
210         return self.__router
211
212     def get_internal_router_interface(self):
213         """
214         Returns the OpenStack internal router interface object
215         :return:
216         """
217         return self.__internal_router_interface
218
219
220 class RouterCreationError(Exception):
221     """
222     Exception to be thrown when an router instance cannot be created
223     """
224
225
226 class RouterSettings(RouterConfig):
227     """
228     Class to hold the configuration settings required for creating OpenStack
229     router objects
230     deprecated
231     """
232
233     def __init__(self, **kwargs):
234         from warnings import warn
235         warn('Use snaps.config.router.RouterConfig instead',
236              DeprecationWarning)
237         super(self.__class__, self).__init__(**kwargs)