441b21a99d0eeefc51d1cb0df557d2a414046673
[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 import six
18
19 from neutronclient.common.exceptions import NotFound, Unauthorized
20
21 from snaps.config.router import RouterConfig
22 from snaps.openstack.openstack_creator import OpenStackNetworkObject
23 from snaps.openstack.utils import neutron_utils
24
25 __author__ = 'spisarski'
26
27 logger = logging.getLogger('OpenStackNetwork')
28
29
30 class OpenStackRouter(OpenStackNetworkObject):
31     """
32     Class responsible for managing a router in OpenStack
33     """
34
35     def __init__(self, os_creds, router_settings):
36         """
37         Constructor - all parameters are required
38         :param os_creds: The credentials to connect with OpenStack
39         :param router_settings: The settings used to create a router object
40                                 (must be an instance of the RouterConfig
41                                 class)
42         """
43         super(self.__class__, self).__init__(os_creds)
44
45         if not router_settings:
46             raise RouterCreationError('router_settings is required')
47
48         self.router_settings = router_settings
49
50         # Attributes instantiated on create()
51         self.__router = None
52         self.__internal_subnets = list()
53         self.__internal_router_interface = None
54
55         # Dict where the port object is the key and any newly created router
56         # interfaces are the value
57         self.__ports = list()
58
59     def initialize(self):
60         """
61         Loads the existing router.
62         :return: the Router domain object
63         """
64         super(self.__class__, self).initialize()
65
66         try:
67             self.__router = neutron_utils.get_router(
68                 self._neutron, self._keystone,
69                 router_settings=self.router_settings,
70                 project_name=self._os_creds.project_name)
71         except Unauthorized as e:
72             logger.warn('Unable to lookup router with name %s - %s',
73                         self.router_settings.name, e)
74
75         if self.__router:
76             for sub_config in self.router_settings.internal_subnets:
77                 internal_subnet = self.__get_internal_subnet(sub_config)
78                 if internal_subnet:
79                     self.__internal_subnets.append(internal_subnet)
80                 else:
81                     raise RouterCreationError(
82                         'Subnet not found with name ' + internal_subnet.name)
83
84             for port_setting in self.router_settings.port_settings:
85                 port = neutron_utils.get_port(
86                     self._neutron, self._keystone, port_settings=port_setting,
87                     project_name=self._os_creds.project_name)
88                 if port:
89                     self.__ports.append(port)
90
91         return self.__router
92
93     def create(self):
94         """
95         Responsible for creating the router.
96         :return: the Router domain object
97         """
98         self.initialize()
99
100         if not self.__router:
101             self.__router = neutron_utils.create_router(
102                 self._neutron, self._os_creds, self.router_settings)
103
104             for sub_config in self.router_settings.internal_subnets:
105                 internal_subnet = self.__get_internal_subnet(sub_config)
106                 if internal_subnet:
107                     self.__internal_subnets.append(internal_subnet)
108                     if internal_subnet:
109                         logger.debug('Adding router to subnet...')
110                         router_intf = neutron_utils.add_interface_router(
111                             self._neutron, self.__router,
112                             subnet=internal_subnet)
113                         self.__internal_router_interface = router_intf
114                 else:
115                     raise RouterCreationError(
116                         'Subnet not found with name ' + internal_subnet.name)
117
118             for port_setting in self.router_settings.port_settings:
119                 port = neutron_utils.get_port(
120                     self._neutron, self._keystone, port_settings=port_setting,
121                     project_name=self._os_creds.project_name)
122                 logger.info(
123                     'Retrieved port %s for router - %s', port_setting.name,
124                     self.router_settings.name)
125                 if port:
126                     self.__ports.append(port)
127
128                 if not port:
129                     port = neutron_utils.create_port(
130                         self._neutron, self._os_creds, port_setting)
131                     if port:
132                         logger.info(
133                             'Created port %s for router - %s',
134                             port_setting.name,
135                             self.router_settings.name)
136                         self.__ports.append(port)
137                         neutron_utils.add_interface_router(
138                             self._neutron, self.__router, port=port)
139                     else:
140                         raise RouterCreationError(
141                             'Error creating port with name - '
142                             + port_setting.name)
143
144         self.__router = neutron_utils.get_router_by_id(
145             self._neutron, self.__router.id)
146         return self.__router
147
148     def __get_internal_subnet(self, sub_config):
149         """
150         returns the Subnet domain object from the subnet configurator
151         :param sub_config:
152         :return:
153         """
154         if isinstance(sub_config, six.text_type):
155             return neutron_utils.get_subnet_by_name(
156                 self._neutron, self._keystone,
157                 subnet_name=sub_config)
158         if isinstance(sub_config, dict):
159             sub_dict = sub_config['subnet']
160             network = neutron_utils.get_network(
161                 self._neutron, self._keystone,
162                 network_name=sub_dict['network_name'],
163                 project_name=sub_dict['project_name'])
164             if network:
165                 return neutron_utils.get_subnet(
166                     self._neutron, network,
167                     subnet_name=sub_dict['subnet_name'])
168
169     def clean(self):
170         """
171         Removes and deletes all items created in reverse order.
172         """
173         for port in self.__ports:
174             logger.info(
175                 'Removing router interface from router %s and port %s',
176                 self.router_settings.name, port.name)
177             try:
178                 neutron_utils.remove_interface_router(self._neutron,
179                                                       self.__router, port=port)
180             except NotFound:
181                 pass
182         self.__ports = list()
183
184         for internal_subnet in self.__internal_subnets:
185             logger.info(
186                 'Removing router interface from router %s and subnet %s',
187                 self.router_settings.name, internal_subnet.name)
188             try:
189                 neutron_utils.remove_interface_router(self._neutron,
190                                                       self.__router,
191                                                       subnet=internal_subnet)
192             except NotFound:
193                 pass
194         self.__internal_subnets = list()
195
196         if self.__router:
197             logger.info('Removing router ' + self.router_settings.name)
198             try:
199                 neutron_utils.delete_router(self._neutron, self.__router)
200             except NotFound:
201                 pass
202             self.__router = None
203
204         super(self.__class__, self).clean()
205
206     def get_router(self):
207         """
208         Returns the OpenStack router object
209         :return:
210         """
211         return self.__router
212
213     def get_internal_router_interface(self):
214         """
215         Returns the OpenStack internal router interface object
216         :return:
217         """
218         return self.__internal_router_interface
219
220
221 class RouterCreationError(Exception):
222     """
223     Exception to be thrown when an router instance cannot be created
224     """
225
226
227 class RouterSettings(RouterConfig):
228     """
229     Class to hold the configuration settings required for creating OpenStack
230     router objects
231     deprecated
232     """
233
234     def __init__(self, **kwargs):
235         from warnings import warn
236         warn('Use snaps.config.router.RouterConfig instead',
237              DeprecationWarning)
238         super(self.__class__, self).__init__(**kwargs)