Ensure project for routers are handled properly.
[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, keystone_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.__keystone = None
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         self.__keystone = keystone_utils.keystone_client(self._os_creds)
67
68         try:
69             self.__router = neutron_utils.get_router(
70                 self._neutron, self.__keystone,
71                 router_settings=self.router_settings,
72                 project_name=self._os_creds.project_name)
73         except Unauthorized as e:
74             logger.warn('Unable to lookup router with name %s - %s',
75                         self.router_settings.name, e)
76
77         if self.__router:
78             for internal_subnet_name in self.router_settings.internal_subnets:
79                 internal_subnet = neutron_utils.get_subnet(
80                     self._neutron, subnet_name=internal_subnet_name)
81                 if internal_subnet:
82                     self.__internal_subnets.append(internal_subnet)
83                 else:
84                     raise RouterCreationError(
85                         'Subnet not found with name ' + internal_subnet_name)
86
87             for port_setting in self.router_settings.port_settings:
88                 port = neutron_utils.get_port(
89                     self._neutron, self.__keystone, port_settings=port_setting,
90                     project_name=self._os_creds.project_name)
91                 if port:
92                     self.__ports.append(port)
93
94         return self.__router
95
96     def create(self):
97         """
98         Responsible for creating the router.
99         :return: the Router domain object
100         """
101         self.initialize()
102
103         if not self.__router:
104             self.__router = neutron_utils.create_router(
105                 self._neutron, self._os_creds, self.router_settings)
106
107             for internal_subnet_name in self.router_settings.internal_subnets:
108                 internal_subnet = neutron_utils.get_subnet(
109                     self._neutron, subnet_name=internal_subnet_name)
110                 if internal_subnet:
111                     self.__internal_subnets.append(internal_subnet)
112                     if internal_subnet:
113                         logger.debug('Adding router to subnet...')
114                         router_intf = neutron_utils.add_interface_router(
115                             self._neutron, self.__router,
116                             subnet=internal_subnet)
117                         self.__internal_router_interface = router_intf
118                 else:
119                     raise RouterCreationError(
120                         'Subnet not found with name ' + internal_subnet_name)
121
122             for port_setting in self.router_settings.port_settings:
123                 port = neutron_utils.get_port(
124                     self._neutron, self.__keystone, port_settings=port_setting,
125                     project_name=self._os_creds.project_name)
126                 logger.info(
127                     'Retrieved port %s for router - %s', port_setting.name,
128                     self.router_settings.name)
129                 if port:
130                     self.__ports.append(port)
131
132                 if not port:
133                     port = neutron_utils.create_port(
134                         self._neutron, self._os_creds, port_setting)
135                     if port:
136                         logger.info(
137                             'Created port %s for router - %s',
138                             port_setting.name,
139                             self.router_settings.name)
140                         self.__ports.append(port)
141                         neutron_utils.add_interface_router(
142                             self._neutron, self.__router, port=port)
143                     else:
144                         raise RouterCreationError(
145                             'Error creating port with name - '
146                             + port_setting.name)
147
148         self.__router = neutron_utils.get_router_by_id(
149             self._neutron, self.__router.id)
150         return self.__router
151
152     def clean(self):
153         """
154         Removes and deletes all items created in reverse order.
155         """
156         for port in self.__ports:
157             logger.info(
158                 'Removing router interface from router %s and port %s',
159                 self.router_settings.name, port.name)
160             try:
161                 neutron_utils.remove_interface_router(self._neutron,
162                                                       self.__router, port=port)
163             except NotFound:
164                 pass
165         self.__ports = list()
166
167         for internal_subnet in self.__internal_subnets:
168             logger.info(
169                 'Removing router interface from router %s and subnet %s',
170                 self.router_settings.name, internal_subnet.name)
171             try:
172                 neutron_utils.remove_interface_router(self._neutron,
173                                                       self.__router,
174                                                       subnet=internal_subnet)
175             except NotFound:
176                 pass
177         self.__internal_subnets = list()
178
179         if self.__router:
180             logger.info('Removing router ' + self.router_settings.name)
181             try:
182                 neutron_utils.delete_router(self._neutron, self.__router)
183             except NotFound:
184                 pass
185             self.__router = None
186
187     def get_router(self):
188         """
189         Returns the OpenStack router object
190         :return:
191         """
192         return self.__router
193
194     def get_internal_router_interface(self):
195         """
196         Returns the OpenStack internal router interface object
197         :return:
198         """
199         return self.__internal_router_interface
200
201
202 class RouterCreationError(Exception):
203     """
204     Exception to be thrown when an router instance cannot be created
205     """
206
207
208 class RouterSettings(RouterConfig):
209     """
210     Class to hold the configuration settings required for creating OpenStack
211     router objects
212     deprecated
213     """
214
215     def __init__(self, **kwargs):
216         from warnings import warn
217         warn('Use snaps.config.router.RouterConfig instead',
218              DeprecationWarning)
219         super(self.__class__, self).__init__(**kwargs)