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