0cf6d4af566d39f4e1676d05f474be9518cdf802
[snaps.git] / snaps / openstack / create_project.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 keystoneclient.exceptions import NotFound, Conflict
18
19 from snaps.openstack.openstack_creator import OpenStackIdentityObject
20 from snaps.openstack.utils import keystone_utils, neutron_utils, nova_utils
21
22 __author__ = 'spisarski'
23
24 logger = logging.getLogger('create_image')
25
26
27 class OpenStackProject(OpenStackIdentityObject):
28     """
29     Class responsible for managing a project/project in OpenStack
30     """
31
32     def __init__(self, os_creds, project_settings):
33         """
34         Constructor
35         :param os_creds: The OpenStack connection credentials
36         :param project_settings: The project's settings
37         :return:
38         """
39         super(self.__class__, self).__init__(os_creds)
40
41         self.project_settings = project_settings
42         self.__project = None
43         self.__role = None
44         self.__role_name = self.project_settings.name + '-role'
45
46     def initialize(self):
47         """
48         Loads the existing Project object if it exists
49         :return: The Project domain object
50         """
51         super(self.__class__, self).initialize()
52
53         self.__project = keystone_utils.get_project(
54             keystone=self._keystone, project_settings=self.project_settings)
55         return self.__project
56
57     def create(self):
58         """
59         Creates a Project/Tenant in OpenStack if it does not already exist
60         :return: The Project domain object
61         """
62         self.initialize()
63
64         if not self.__project:
65             self.__project = keystone_utils.create_project(
66                 self._keystone, self.project_settings)
67             for username in self.project_settings.users:
68                 user = keystone_utils.get_user(self._keystone, username)
69                 if user:
70                     try:
71                         self.assoc_user(user)
72                     except Conflict as e:
73                         logger.warn('Unable to associate user %s due to %s',
74                                     user.name, e)
75
76         return self.__project
77
78     def clean(self):
79         """
80         Cleanse environment of all artifacts
81         :return: void
82         """
83         if self.__project:
84             # Delete security group 'default' if exists
85             neutron = neutron_utils.neutron_client(self._os_creds)
86             default_sec_grp = neutron_utils.get_security_group(
87                 neutron, sec_grp_name='default',
88                 project_id=self.__project.id)
89             if default_sec_grp:
90                 try:
91                     neutron_utils.delete_security_group(
92                         neutron, default_sec_grp)
93                 except:
94                     pass
95
96             # Delete Project
97             try:
98                 keystone_utils.delete_project(self._keystone, self.__project)
99             except NotFound:
100                 pass
101             self.__project = None
102
103         if self.__role:
104             try:
105                 keystone_utils.delete_role(self._keystone, self.__role)
106             except NotFound:
107                 pass
108             self.__project = None
109
110         # Final role check in case init was done from an existing instance
111         role = keystone_utils.get_role_by_name(
112             self._keystone, self.__role_name)
113         if role:
114             keystone_utils.delete_role(self._keystone, role)
115
116     def get_project(self):
117         """
118         Returns the OpenStack project object populated on create()
119         :return:
120         """
121         return self.__project
122
123     def assoc_user(self, user):
124         """
125         The user object to associate with the project
126         :param user: the OpenStack User domain object to associate with project
127         :return:
128         """
129         if not self.__role:
130             self.__role = keystone_utils.get_role_by_name(
131                 self._keystone, self.__role_name)
132             if not self.__role:
133                 self.__role = keystone_utils.create_role(
134                     self._keystone, self.__role_name)
135
136         keystone_utils.grant_user_role_to_project(self._keystone, self.__role,
137                                                   user, self.__project)
138
139     def get_compute_quotas(self):
140         """
141         Returns the compute quotas as an instance of the ComputeQuotas class
142         :return:
143         """
144         nova = nova_utils.nova_client(self._os_creds)
145         return nova_utils.get_compute_quotas(nova, self.__project.id)
146
147     def get_network_quotas(self):
148         """
149         Returns the network quotas as an instance of the NetworkQuotas class
150         :return:
151         """
152         neutron = neutron_utils.neutron_client(self._os_creds)
153         return neutron_utils.get_network_quotas(neutron, self.__project.id)
154
155     def update_compute_quotas(self, compute_quotas):
156         """
157         Updates the compute quotas for this project
158         :param compute_quotas: a ComputeQuotas object.
159         """
160         nova = nova_utils.nova_client(self._os_creds)
161         nova_utils.update_quotas(nova, self.__project.id, compute_quotas)
162
163     def update_network_quotas(self, network_quotas):
164         """
165         Updates the network quotas for this project
166         :param network_quotas: a NetworkQuotas object.
167         """
168         neutron = neutron_utils.neutron_client(self._os_creds)
169         neutron_utils.update_quotas(neutron, self.__project.id, network_quotas)
170
171
172 class ProjectSettings:
173     """
174     Class to hold the configuration settings required for creating OpenStack
175     project objects
176     """
177
178     def __init__(self, **kwargs):
179
180         """
181         Constructor
182         :param name: the project's name (required)
183         :param domain or domain_name: the project's domain name
184                                       (default = 'Default').
185                                       Field is used for v3 clients
186         :param description: the description (optional)
187         :param users: list of users to associat project to (optional)
188         :param enabled: denotes whether or not the user is enabled
189                         (default True)
190         """
191
192         self.name = kwargs.get('name')
193         self.domain_name = kwargs.get(
194             'domain', kwargs.get('domain', 'Default'))
195
196         self.description = kwargs.get('description')
197         if kwargs.get('enabled') is not None:
198             self.enabled = kwargs['enabled']
199         else:
200             self.enabled = True
201
202         self.users = kwargs.get('users', list())
203
204         if not self.name:
205             raise ProjectSettingsError(
206                 "The attribute name is required for ProjectSettings")
207
208
209 class ProjectSettingsError(Exception):
210     """
211     Exception to be thrown when project settings attributes are incorrect
212     """