Browse Source

database layer

Change-Id: I6ff5e8773e8eb158e61f5eead8b1c76f7e4df834
Kanagaraj Manickam 3 years ago
parent
commit
363a76281d

+ 3
- 5
README.rst View File

@@ -1,8 +1,6 @@
1
-===============================
2
-namos
3
-===============================
4
-
5
-OpenStack Service, Device manager
1
+=========================
2
+namos - OpenStack manager
3
+=========================
6 4
 
7 5
 * Free software: Apache license
8 6
 * Documentation: http://docs.openstack.org/developer/namos

+ 2
- 0
etc/namos.conf View File

@@ -0,0 +1,2 @@
1
+[database]
2
+connection = mysql+pymysql://root:password@172.241.0.101/namos?charset=utf8

+ 0
- 0
namos/cmd/__init__.py View File


+ 110
- 0
namos/cmd/manage.py View File

@@ -0,0 +1,110 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+import sys
16
+
17
+from oslo_config import cfg
18
+
19
+from namos.common import config
20
+from namos.db import sample
21
+from namos.db.sqlalchemy import migration
22
+
23
+
24
+CONF = cfg.CONF
25
+MANAGE_COMMAND_NAME = 'namos-manage'
26
+
27
+
28
+class DBCommand(object):
29
+
30
+    def upgrade(self):
31
+        migration.upgrade(CONF.command.revision)
32
+
33
+    def downgrade(self):
34
+        migration.downgrade(CONF.command.revision)
35
+
36
+    def revision(self):
37
+        migration.revision(CONF.command.message, CONF.command.autogenerate)
38
+
39
+    def stamp(self):
40
+        migration.stamp(CONF.command.revision)
41
+
42
+    def version(self):
43
+        print(migration.version())
44
+
45
+    def create_schema(self):
46
+        migration.create_schema()
47
+
48
+    def history(self):
49
+        migration.history()
50
+
51
+    def demo_data(self):
52
+        if CONF.command.purge:
53
+            sample.purge_demo_data()
54
+        else:
55
+            sample.populate_demo_data()
56
+
57
+
58
+def add_command_parsers(subparsers):
59
+    command_object = DBCommand()
60
+
61
+    parser = subparsers.add_parser('upgrade')
62
+    parser.set_defaults(func=command_object.upgrade)
63
+    parser.add_argument('--revision', nargs='?')
64
+
65
+    parser = subparsers.add_parser('downgrade')
66
+    parser.set_defaults(func=command_object.downgrade)
67
+    parser.add_argument('--revision', nargs='?')
68
+
69
+    parser = subparsers.add_parser('stamp')
70
+    parser.add_argument('--revision', nargs='?')
71
+    parser.set_defaults(func=command_object.stamp)
72
+
73
+    parser = subparsers.add_parser('revision')
74
+    parser.add_argument('-m', '--message')
75
+    parser.add_argument('--autogenerate', action='store_true')
76
+    parser.set_defaults(func=command_object.revision)
77
+
78
+    parser = subparsers.add_parser('version')
79
+    parser.set_defaults(func=command_object.version)
80
+
81
+    parser = subparsers.add_parser('history')
82
+    parser.set_defaults(func=command_object.history)
83
+
84
+    parser = subparsers.add_parser('create_schema')
85
+    parser.set_defaults(func=command_object.create_schema)
86
+
87
+    parser = subparsers.add_parser('demo_data')
88
+    parser.add_argument('-p', '--purge', action='store_true')
89
+    parser.set_defaults(func=command_object.demo_data)
90
+
91
+
92
+command_opt = cfg.SubCommandOpt('command',
93
+                                title='Command',
94
+                                help='Available commands',
95
+                                handler=add_command_parsers)
96
+
97
+CONF.register_cli_opt(command_opt)
98
+# olso mandates to initialize the config after cli opt registration
99
+config.init_conf(prog=MANAGE_COMMAND_NAME)
100
+
101
+
102
+def main():
103
+    try:
104
+        CONF.command.func()
105
+    except Exception as e:
106
+        sys.exit("ERROR: %s" % e)
107
+
108
+
109
+if __name__ == '__main__':
110
+    main()

+ 0
- 0
namos/common/__init__.py View File


+ 36
- 0
namos/common/config.py View File

@@ -0,0 +1,36 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+from oslo_config import cfg
16
+from oslo_log import log as logging
17
+
18
+import namos
19
+
20
+PROJECT_NAME = 'namos'
21
+VERSION = namos.__version__
22
+
23
+CONF = cfg.CONF
24
+
25
+
26
+def init_conf(prog):
27
+    CONF(project=PROJECT_NAME,
28
+         version=VERSION,
29
+         prog=prog)
30
+
31
+
32
+def setup_log(prog=PROJECT_NAME):
33
+    logging.register_options(cfg.CONF)
34
+    logging.setup(cfg.CONF,
35
+                  prog,
36
+                  version=VERSION)

+ 121
- 0
namos/common/exception.py View File

@@ -0,0 +1,121 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+import json
16
+import logging
17
+import six
18
+
19
+
20
+LOG = logging.getLogger(__name__)
21
+
22
+
23
+class NamosException(Exception):
24
+    msg_fmt = ("An unknown exception occurred.")
25
+    message = None
26
+    error_code = None
27
+    http_status_code = None
28
+    data = {}
29
+
30
+    def __init__(self, **kwargs):
31
+        self.kwargs = kwargs
32
+
33
+        try:
34
+            if kwargs.get('message') is not None:
35
+                self.message = kwargs['message']
36
+            else:
37
+                self.message = json.dumps(
38
+                    {'error_code': self.error_code,
39
+                     'message': self.msg_fmt % kwargs,
40
+                     'http_code': self.http_status_code,
41
+                     'data': kwargs})
42
+            if kwargs.get('data') is not None:
43
+                self.data = kwargs['data']
44
+        except KeyError:
45
+            self.message = self.msg_fmt
46
+            LOG.exception(('Exception in string format operation'))
47
+            for name, value in six.iteritems(kwargs):
48
+                LOG.error("%s: %s" % (name, value))  # noqa
49
+
50
+    def __str__(self):
51
+        return unicode(self.message).encode('UTF-8')
52
+
53
+    def __unicode__(self):
54
+        return unicode(self.message)
55
+
56
+    def __deepcopy__(self, memo):
57
+        return self.__class__(**self.kwargs)
58
+
59
+
60
+class NotFound(NamosException):
61
+    msg_fmt = ("Not Found")
62
+    error_code = -1
63
+    http_status_code = 404
64
+
65
+
66
+class RegionNotFound(NotFound):
67
+    msg_fmt = ("Region %(region_id)s does not found")
68
+    error_code = 0x01001
69
+
70
+
71
+class RegionAlreadyExist(NamosException):
72
+    msg_fmt = ("Region %(region_id)s already exists")
73
+    error_code = 0x01002
74
+    http_status_code = 403
75
+
76
+
77
+class DeviceNotFound(NotFound):
78
+    msg_fmt = ("Device %(device_id)s does not found")
79
+    error_code = 0x02001
80
+
81
+
82
+class DeviceEndpointNotFound(NotFound):
83
+    msg_fmt = ("Device Endpoint %(device_endpoint_id)s does not found")
84
+    error_code = 0x03001
85
+
86
+
87
+class DeviceDriverNotFound(NotFound):
88
+    msg_fmt = ("Device Driver %(device_driver_id)s does not found")
89
+    error_code = 0x04001
90
+
91
+
92
+class DeviceDriverClassNotFound(NotFound):
93
+    msg_fmt = ("Device Driver Class %(device_driver_class_id)s "
94
+               "does not found")
95
+    error_code = 0x05001
96
+
97
+
98
+class ServiceNotFound(NotFound):
99
+    msg_fmt = ("Service %(service_id)s does not found")
100
+    error_code = 0x06001
101
+
102
+
103
+class ServiceNodeNotFound(NotFound):
104
+    msg_fmt = ("Service Node %(service_node_id)s does not found")
105
+    error_code = 0x07001
106
+
107
+
108
+class ServiceComponentNotFound(NotFound):
109
+    msg_fmt = ("Service Component %(service_component_id)s does not found")
110
+    error_code = 0x08001
111
+
112
+
113
+class ServiceWorkerNotFound(NotFound):
114
+    msg_fmt = ("Service Worker %(service_worker_id)s "
115
+               "does not found")
116
+    error_code = 0x09001
117
+
118
+
119
+class ConfigNotFound(NotFound):
120
+    msg_fmt = ("Config %(config_id)s does not found")
121
+    error_code = 0x0a001

+ 0
- 0
namos/db/__init__.py View File


+ 367
- 0
namos/db/api.py View File

@@ -0,0 +1,367 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+
16
+from oslo_config import cfg
17
+from oslo_db import api
18
+
19
+CONF = cfg.CONF
20
+
21
+_BACKEND_MAPPING = {'sqlalchemy': 'namos.db.sqlalchemy.api'}
22
+
23
+IMPL = api.DBAPI.from_config(CONF, backend_mapping=_BACKEND_MAPPING)
24
+
25
+
26
+def get_engine():
27
+    return IMPL.get_engine()
28
+
29
+
30
+def get_session():
31
+    return IMPL.get_session()
32
+
33
+
34
+# TODO(kanagaraj-manickam): Add db wrapper function to capture the db
35
+# exception in each of the below methods and log it
36
+
37
+# Region
38
+
39
+def region_create(context, values):
40
+    return IMPL.region_create(context, values)
41
+
42
+
43
+def region_update(context, _id, values):
44
+    return IMPL.region_update(context, _id, values)
45
+
46
+
47
+def region_get(context, _id):
48
+    return IMPL.region_get(context, _id)
49
+
50
+
51
+def region_get_by_name(context, name):
52
+    return IMPL.region_get_by_name(context, name)
53
+
54
+
55
+def region_get_all(context):
56
+    return IMPL.region_get_all(context)
57
+
58
+
59
+def region_delete(context, _id):
60
+    return IMPL.region_delete(context, _id)
61
+
62
+
63
+# Device
64
+
65
+def device_create(context, values):
66
+    return IMPL.device_create(context, values)
67
+
68
+
69
+def device_update(context, _id, values):
70
+    return IMPL.device_update(context, _id, values)
71
+
72
+
73
+def device_get(context, _id):
74
+    return IMPL.device_get(context, _id)
75
+
76
+
77
+def device_get_by_name(context, name):
78
+    return IMPL.device_get_by_name(context, name)
79
+
80
+
81
+def device_get_all(context):
82
+    return IMPL.device_get_all(context)
83
+
84
+
85
+def device_delete(context, _id):
86
+    return IMPL.device_delete(context, _id)
87
+
88
+
89
+# Device Endpoint
90
+
91
+def device_endpoint_create(context, values):
92
+    return IMPL.device_endpoint_create(context, values)
93
+
94
+
95
+def device_endpoint_update(context, _id, values):
96
+    return IMPL.device_endpoint_update(context, _id, values)
97
+
98
+
99
+def device_endpoint_get(context, _id):
100
+    return IMPL.device_endpoint_get(context, _id)
101
+
102
+
103
+def device_endpoint_get_by_name(context, name):
104
+    return IMPL.device_endpoint_get_by_name(context, name)
105
+
106
+
107
+def device_endpoint_get_by_device_type(context,
108
+                                       device_id,
109
+                                       type=None,
110
+                                       name=None):
111
+    return IMPL.device_endpoint_get_by_device_type(context, device_id,
112
+                                                   type, name)
113
+
114
+
115
+def device_endpoint_get_all(context):
116
+    return IMPL.device_endpoint_get_all(context)
117
+
118
+
119
+def device_endpoint_delete(context, _id):
120
+    return IMPL.device_endpoint_delete(context, _id)
121
+
122
+
123
+# Device Driver
124
+
125
+def device_driver_create(context, values):
126
+    return IMPL.device_driver_create(context, values)
127
+
128
+
129
+def device_driver_update(context, _id, values):
130
+    return IMPL.device_driver_update(context, _id, values)
131
+
132
+
133
+def device_driver_get(context, _id):
134
+    return IMPL.device_driver_get(context, _id)
135
+
136
+
137
+def device_driver_get_by_name(context, name):
138
+    return IMPL.device_driver_get_by_name(context, name)
139
+
140
+
141
+def device_driver_get_by_device_endpoint_service_worker(
142
+        context,
143
+        device_id=None,
144
+        endpoint_id=None,
145
+        device_driver_class_id=None,
146
+        service_worker_id=None):
147
+    return IMPL.device_driver_get_by_device_endpoint_service_worker(
148
+        context,
149
+        device_id,
150
+        endpoint_id,
151
+        device_driver_class_id,
152
+        service_worker_id)
153
+
154
+
155
+def device_driver_get_all(context):
156
+    return IMPL.device_driver_get_all(context)
157
+
158
+
159
+def device_driver_delete(context, _id):
160
+    return IMPL.device_driver_delete(context, _id)
161
+
162
+
163
+# Device Driver Class
164
+
165
+def device_driver_class_create(context, values):
166
+    return IMPL.device_driver_class_create(context, values)
167
+
168
+
169
+def device_driver_class_update(context, _id, values):
170
+    return IMPL.device_driver_class_update(context, _id, values)
171
+
172
+
173
+def device_driver_class_get(context, _id):
174
+    return IMPL.device_driver_class_get(context, _id)
175
+
176
+
177
+def device_driver_class_get_by_name(context, name):
178
+    return IMPL.device_driver_class_get_by_name(context, name)
179
+
180
+
181
+def device_driver_class_get_all(context):
182
+    return IMPL.device_driver_class_get_all(context)
183
+
184
+
185
+def device_driver_class_delete(context, _id):
186
+    return IMPL.device_driver_class_delete(context, _id)
187
+
188
+
189
+# Service
190
+
191
+def service_create(context, values):
192
+    return IMPL.service_create(context, values)
193
+
194
+
195
+def service_update(context, _id, values):
196
+    return IMPL.service_update(context, _id, values)
197
+
198
+
199
+def service_get(context, _id):
200
+    return IMPL.service_get(context, _id)
201
+
202
+
203
+def service_get_by_name(context, name):
204
+    return IMPL.service_get_by_name(context, name)
205
+
206
+
207
+def service_get_all(context):
208
+    return IMPL.service_get_all(context)
209
+
210
+
211
+def service_delete(context, _id):
212
+    return IMPL.service_delete(context, _id)
213
+
214
+
215
+# Service Node
216
+
217
+def service_node_create(context, values):
218
+    return IMPL.service_node_create(context, values)
219
+
220
+
221
+def service_node_update(context, _id, values):
222
+    return IMPL.service_node_update(context, _id, values)
223
+
224
+
225
+def service_node_get(context, _id):
226
+    return IMPL.service_node_get(context, _id)
227
+
228
+
229
+def service_node_get_by_name(context, name):
230
+    return IMPL.service_node_get_by_name(context, name)
231
+
232
+
233
+def service_node_get_all(context):
234
+    return IMPL.service_node_get_all(context)
235
+
236
+
237
+def service_node_delete(context, _id):
238
+    return IMPL.service_node_delete(context, _id)
239
+
240
+
241
+# Service Component
242
+
243
+def service_component_create(context, values):
244
+    return IMPL.service_component_create(context, values)
245
+
246
+
247
+def service_component_update(context, _id, values):
248
+    return IMPL.service_component_update(context, _id, values)
249
+
250
+
251
+def service_component_get(context, _id):
252
+    return IMPL.service_component_get(context, _id)
253
+
254
+
255
+def service_component_get_by_name(context, name):
256
+    return IMPL.service_component_get_by_name(context, name)
257
+
258
+
259
+def service_component_get_all_by_node_for_service(context,
260
+                                                  node_id,
261
+                                                  service_id=None,
262
+                                                  name=None):
263
+    return IMPL.service_component_get_all_by_node_for_service(context,
264
+                                                              node_id,
265
+                                                              service_id,
266
+                                                              name)
267
+
268
+
269
+def service_component_get_all(context):
270
+    return IMPL.service_component_get_all(context)
271
+
272
+
273
+def service_component_delete(context, _id):
274
+    return IMPL.service_component_delete(context, _id)
275
+
276
+
277
+#  Service Worker
278
+def service_worker_create(context, values):
279
+    return IMPL.service_worker_create(context, values)
280
+
281
+
282
+def service_worker_update(context, _id, values):
283
+    return IMPL.service_worker_update(context, _id, values)
284
+
285
+
286
+def service_worker_get(context, _id):
287
+    return IMPL.service_worker_get(context, _id)
288
+
289
+
290
+def service_worker_get_by_name(context, name):
291
+    return IMPL.service_worker_get_by_name(context, name)
292
+
293
+
294
+def service_worker_get_by_host_for_service_component(context,
295
+                                                     service_component_id,
296
+                                                     host=None):
297
+    return IMPL.service_worker_get_by_host_for_service_component(
298
+        context,
299
+        service_component_id,
300
+        host)
301
+
302
+
303
+def service_worker_get_all(context):
304
+    return IMPL.service_worker_get_all(context)
305
+
306
+
307
+def service_worker_delete(context, _id):
308
+    return IMPL.service_worker_delete(context, _id)
309
+
310
+
311
+#  Config
312
+
313
+def config_create(context, values):
314
+    return IMPL.config_create(context, values)
315
+
316
+
317
+def config_update(context, _id, values):
318
+    return IMPL.config_update(context, _id, values)
319
+
320
+
321
+def config_get(context, _id):
322
+    return IMPL.config_get(context, _id)
323
+
324
+
325
+def config_get_by_name(context, name):
326
+    return IMPL.config_get_by_name(context, name)
327
+
328
+
329
+def config_get_by_name_for_service_worker(context,
330
+                                          service_worker_id,
331
+                                          name=None):
332
+    return IMPL.config_get_by_name_for_service_worker(context,
333
+                                                      service_worker_id,
334
+                                                      name)
335
+
336
+
337
+def config_get_all(context):
338
+    return IMPL.config_get_all(context)
339
+
340
+
341
+def config_delete(context, _id):
342
+    return IMPL.config_delete(context, _id)
343
+
344
+
345
+def service_perspective_get(context, service_id,
346
+                            include_details=False):
347
+    return IMPL.service_perspective_get(context,
348
+                                        service_id,
349
+                                        include_details)
350
+
351
+
352
+def device_perspective_get(context, device_id,
353
+                           include_details=False):
354
+    return IMPL.device_perspective_get(context,
355
+                                       device_id,
356
+                                       include_details)
357
+
358
+
359
+def region_perspective_get(context, region_id,
360
+                           include_details=False):
361
+    return IMPL.region_perspective_get(context,
362
+                                       region_id,
363
+                                       include_details)
364
+
365
+
366
+def infra_perspective_get(context):
367
+    return IMPL.infra_perspective_get(context)

+ 18
- 0
namos/db/migration.py View File

@@ -0,0 +1,18 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+"""Database setup and migration commands."""
16
+
17
+# TODO(kanagaraj-manickam) Introduce the abstraction here and consume it
18
+# in db_sync to make the db backend as portable

+ 1435
- 0
namos/db/openstack_drivers.py
File diff suppressed because it is too large
View File


+ 444
- 0
namos/db/sample.py View File

@@ -0,0 +1,444 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+from namos.db import api
16
+
17
+REGION_LIST = [
18
+    {'f7dcd175-27ef-46b5-997f-e6e572f320af':
19
+         {'name': 'RegionOne',
20
+          'keystone_region_id': 'region_one',
21
+          'extra': {'location': 'bangalore'}}
22
+    },
23
+    {'f7dcd175-27ef-46b5-997f-e6e572f320b0':
24
+         {'name': 'RegionTwo',
25
+          'keystone_region_id': 'region_two',
26
+          'extra': {'location': 'chennai'}}
27
+    }
28
+]
29
+
30
+DEVICE_LIST = [
31
+    # vCenter
32
+    {'91007d3c-9c95-40c5-8f94-c7b071f9b577':
33
+        {
34
+            'name': 'Vmware_vCenter_1',
35
+            'display_name': 'VMWare vCenter 1',
36
+            'description': 'vCenter 5.0',
37
+            'status': 'active',
38
+            'extra': {'owner': 'mkr1481@namos.com'},
39
+            'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'}
40
+        },
41
+    # Clusters
42
+    {'d468ea2e-74f6-4a55-a7f4-a56d18e91c66':
43
+         {
44
+             'name': 'vmware_vc_Cluster_1',
45
+             'display_name': 'VMWare vCenter 1 Cluster 1',
46
+             'description': 'Cluster 1 having 3 hosts',
47
+             'status': 'active',
48
+             'extra': {'owner': 'mkr1481@namos.com',
49
+                    'vcpus': 1000,
50
+                    'ram_in_gb': 1024},
51
+          'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577',
52
+          'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'}
53
+    },
54
+    {'6c97f476-8e27-4e21-8528-a5ec236306f3':
55
+         {'name': 'vmware_vc_Cluster_2',
56
+          'display_name': 'VMWare vCenter 1 Cluster 2',
57
+          'description': 'Cluster 2 having 5 hosts',
58
+          'status': 'active',
59
+          'extra': {'owner': 'mkr1481@namos.com'},
60
+          'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577',
61
+          'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'}
62
+    },
63
+    # Datastores
64
+    {'fdab6c51-38fb-4fb1-a76f-9c243a8b8296':
65
+         {'name': 'Vmware_vCenter_1_datastore_1',
66
+          'display_name': 'VMWare vCenter 1 datastore 1',
67
+          'description': 'vCenter 5.0 Datastore created from FC',
68
+          'status': 'active',
69
+          'extra': {'owner': 'mkr1481@namos.com',
70
+                    'size_in_gb': '102400'},
71
+          'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577',
72
+          'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'}
73
+    },
74
+    {'05b935b3-942c-439c-a6a4-9c3c73285430':
75
+         {'name': 'Vmware_vCenter_1_datastore_2',
76
+          'display_name': 'VMWare vCenter 1 datastore 2',
77
+          'description': 'vCenter 5.0 Datastore created from FC',
78
+          'status': 'active',
79
+          'extra': {'owner': 'mkr1481@namos.com',
80
+                    'size_in_gb': '10240'},
81
+          'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577',
82
+          'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'}
83
+    },
84
+    # Switch
85
+    {'f062556b-45c4-417d-80fa-4283b9c58da3':
86
+         {'name': 'Vmware_vCenter_1_switch_1',
87
+          'display_name': 'VMWare vCenter 1 Dist. vSwitch 1',
88
+          'description': 'vCenter 5.0 distributed virtual switch',
89
+          'status': 'active',
90
+          'extra': {'owner': 'mkr1481@namos.com'},
91
+          'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577',
92
+          'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'}
93
+    }
94
+]
95
+
96
+ENDPOINT_LIST = [
97
+    {'7403bf80-9376-4081-89ee-d2501661ca84':{
98
+        'name': 'vcenter1_connection',
99
+        'connection': {'host_ip': '10.1.1.3',
100
+                       'host_port': 443,
101
+                       'host_username': 'adminstrator',
102
+                       'host_password': 'password'},
103
+        'device_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577'
104
+    }}
105
+]
106
+
107
+
108
+DEVICE_DRIVER_CLASS_LIST = [
109
+    {'0664e8c0-ff02-427e-8fa3-8788c017ad84': {
110
+        'python_class': 'nova...vcdriver',
111
+        'type': 'compute',
112
+        'vendor': 'vmware-community'
113
+    }},
114
+    {'11caf99c-f820-4266-a461-5a15437a8144': {
115
+        'python_class': 'cinder...vmdkdriver',
116
+        'type': 'volume',
117
+        'vendor': 'vmware-community'
118
+    }},
119
+    {'bb99ea96-fe6b-49e6-a761-faea92b79f75': {
120
+        'python_class': 'neutron...nsxdriver',
121
+        'type': 'network',
122
+        'vendor': 'vmware-community'
123
+    }}
124
+]
125
+
126
+DEVICE_DRIVER_LIST = [
127
+    # nova
128
+    {'3c089cdb-e1d5-4182-9a8e-cef9899fd7e5':{
129
+        'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84',
130
+        'device_driver_class_id':'0664e8c0-ff02-427e-8fa3-8788c017ad84',
131
+        'device_id': 'd468ea2e-74f6-4a55-a7f4-a56d18e91c66'
132
+    }},
133
+    # nova
134
+    {'4e0360ae-0728-4bfd-a557-3ad867231787':{
135
+        'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84',
136
+        'device_driver_class_id':'0664e8c0-ff02-427e-8fa3-8788c017ad84',
137
+        'device_id': '6c97f476-8e27-4e21-8528-a5ec236306f3'
138
+    }},
139
+    # cinder
140
+    {'92d5e2c1-511b-4837-a57d-5e6ee723060c':{
141
+        'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84',
142
+        'device_driver_class_id':'11caf99c-f820-4266-a461-5a15437a8144',
143
+        'device_id': 'fdab6c51-38fb-4fb1-a76f-9c243a8b8296'
144
+    }},
145
+    # cinder
146
+    {'f3d807a0-eff0-4473-8ae5-594967136e05':{
147
+        'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84',
148
+        'python_class_id':'11caf99c-f820-4266-a461-5a15437a8144',
149
+        'device_id': '05b935b3-942c-439c-a6a4-9c3c73285430'
150
+    }},
151
+    # neutron
152
+    {'f27eb548-929c-45e2-a2a7-dc123e2a1bc7':{
153
+        'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84',
154
+        'python_class_id':'bb99ea96-fe6b-49e6-a761-faea92b79f75',
155
+        'device_id': 'f062556b-45c4-417d-80fa-4283b9c58da3'
156
+    }}
157
+]
158
+
159
+
160
+SERVICE_LIST =[
161
+    {'11367a37-976f-468a-b8dd-77b28ee63cf4': {
162
+        'name': 'nova_service',
163
+        'keystone_service_id': 'b9c2549f-f685-4bc2-92e9-ba8af9c18599'
164
+    }},
165
+    {'809e04c1-2f3b-43af-9677-3428a0154216': {
166
+        'name': 'cinder_service',
167
+        'keystone_service_id': '9cc4c374-abb5-4bdc-9129-f0fa4bba0e0b'
168
+    }},
169
+    {'3495fa07-39d9-4d87-9f97-0a582a3e25c3': {
170
+        'name': 'neutron_service',
171
+        'keystone_service_id': 'b24e2884-75bc-4876-81d1-5b4fb6e92afc'
172
+    }}
173
+]
174
+
175
+SERVICE_NODE_LIST = [
176
+    {
177
+        'a5073d58-2dbb-4146-b47c-4e5f7dc11fbe': {
178
+            'name': 'd_network_node_1',
179
+            'fqdn': 'network_node_1.devstack1.abc.com',
180
+            'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'
181
+        }
182
+    },
183
+    {
184
+        '4e99a641-dbe9-416e-8c0a-78015dc55a2a': {
185
+            'name': 'd_compute_node_1',
186
+            'fqdn': 'compute_node_1.devstack.abc.com',
187
+            'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'
188
+        }
189
+    },
190
+    {
191
+        'b92f4811-7970-421b-a611-d51c62972388': {
192
+            'name': 'd_cloud-controller-1',
193
+            'fqdn': 'cloud_controller_1.devstack1.abc.com',
194
+            'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'
195
+        }
196
+    },
197
+    {
198
+        'e5913cd3-a416-40e1-889f-1a1b1c53001c': {
199
+            'name': 'd_storage_node_1',
200
+            'fqdn': 'storage_node_1.devstack.abc.com',
201
+            'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'
202
+        }
203
+    }
204
+]
205
+
206
+
207
+SERVICE_COMPONENT_LIST = [
208
+    # nova
209
+    {
210
+        '7259a9ff-2e6f-4e8d-b2fb-a529188825dd': {
211
+            'name': 'd_nova-compute',
212
+            'node_id': '4e99a641-dbe9-416e-8c0a-78015dc55a2a',
213
+            'service_id': '11367a37-976f-468a-b8dd-77b28ee63cf4'
214
+        }
215
+    },
216
+    {
217
+        'e5e366ea-9029-4ba0-8bbc-f658e642aa54': {
218
+            'name': 'd_nova-scheduler',
219
+            'node_id': 'b92f4811-7970-421b-a611-d51c62972388',
220
+            'service_id': '11367a37-976f-468a-b8dd-77b28ee63cf4'
221
+        }
222
+    },
223
+    {
224
+        'f7813622-85ee-4588-871d-42c3128fa14f': {
225
+            'name': 'd_nova-api',
226
+            'node_id': 'b92f4811-7970-421b-a611-d51c62972388',
227
+            'service_id': '11367a37-976f-468a-b8dd-77b28ee63cf4'
228
+        }
229
+    },
230
+    # cinder
231
+    {
232
+        'b0e9ac3f-5600-406c-95e4-f698b1eecfc6': {
233
+            'name': 'd_cinder-volume',
234
+            'node_id': 'e5913cd3-a416-40e1-889f-1a1b1c53001c',
235
+            'service_id': '809e04c1-2f3b-43af-9677-3428a0154216'
236
+        }
237
+    },
238
+    # neutron
239
+    {
240
+        '54f608bd-fb01-4614-9653-acbb803aeaf7':{
241
+            'name': 'd_neutron-agent',
242
+            'node_id': 'a5073d58-2dbb-4146-b47c-4e5f7dc11fbe',
243
+            'service_id': '3495fa07-39d9-4d87-9f97-0a582a3e25c3'
244
+        }
245
+    }
246
+]
247
+
248
+SERVICE_WORKER_LIST = [
249
+    # cluster-1
250
+    {
251
+        '65dbd695-fa92-4950-b8b4-d46aa0408f6a': {
252
+            'name': 'd_nova-compute-esx-cluster1',
253
+            'pid': '1233454343',
254
+            'host': 'd_nova-compute-esx-cluster1',
255
+            'service_component_id': '7259a9ff-2e6f-4e8d-b2fb-a529188825dd',
256
+            'device_driver_id': '3c089cdb-e1d5-4182-9a8e-cef9899fd7e5'
257
+        }
258
+    },
259
+    # cluster-2
260
+    {
261
+        '50d2c0c6-741d-4108-a3a2-2090eaa0be37': {
262
+            'name': 'd_nova-compute-esx-cluster2',
263
+            'pid': '1233454344',
264
+            'host': 'd_nova-compute-esx-cluster2',
265
+            'service_component_id': '7259a9ff-2e6f-4e8d-b2fb-a529188825dd',
266
+            'device_driver_id': '4e0360ae-0728-4bfd-a557-3ad867231787'
267
+        }
268
+    },
269
+    # datastore-1
270
+    {
271
+        '77e3ee16-fa2b-4e12-ad1c-226971d1a482': {
272
+            'name': 'd_cinder-volume-vmdk-1',
273
+            'pid': '09878654',
274
+            'host': 'd_cinder-volume-vmdk-1',
275
+            'service_component_id': 'b0e9ac3f-5600-406c-95e4-f698b1eecfc6',
276
+            'device_driver_id': '92d5e2c1-511b-4837-a57d-5e6ee723060c'
277
+        }
278
+    },
279
+    # datastore-2
280
+    {
281
+        '8633ce68-2b02-4efd-983c-49a460f6d7ef': {
282
+            'name': 'd_cinder-volume-vmdk-2',
283
+            'pid': '4353453',
284
+            'host': 'd_cinder-volume-vmdk-2',
285
+            'service_component_id': 'b0e9ac3f-5600-406c-95e4-f698b1eecfc6',
286
+            'device_driver_id': 'f3d807a0-eff0-4473-8ae5-594967136e05'
287
+        }
288
+    },
289
+    # vswitch
290
+    {
291
+        '5a3ac5b9-9186-45d8-928c-9e702368dfb4': {
292
+            'name': 'd_neutron-agent',
293
+            'pid': '2359234',
294
+            'host': 'd_neutron-agent',
295
+            'service_component_id': '54f608bd-fb01-4614-9653-acbb803aeaf7',
296
+            'device_driver_id': 'f27eb548-929c-45e2-a2a7-dc123e2a1bc7'
297
+        }
298
+    },
299
+]
300
+
301
+CONFIG_LIST = [
302
+    {
303
+        'dc6aa02f-ba70-4410-a59c-5e113e629fe5': {
304
+            'name':'vmware.host_ip',
305
+            'value':'10.1.0.1',
306
+            'help': 'VMWare vcenter IP address',
307
+            'default':'',
308
+            'type':'String',
309
+            'required':True,
310
+            'secret': False,
311
+            'config_file':'/etc/nova/nova.conf',
312
+            'service_worker_id': '65dbd695-fa92-4950-b8b4-d46aa0408f6a'
313
+        }
314
+    },
315
+    {
316
+        'dc6aa02f-ba70-4410-a59c-5e113e629f10': {
317
+            'name':'vmware.host_username',
318
+            'value':'Administraotr',
319
+            'help': 'VMWare vcenter Username',
320
+            'default':'Administrator',
321
+            'type':'String',
322
+            'required':True,
323
+            'secret': False,
324
+            'file':'/etc/nova/nova.conf',
325
+            'service_worker_id': '65dbd695-fa92-4950-b8b4-d46aa0408f6a'
326
+        }
327
+    },
328
+    {
329
+        'dc6aa02f-ba70-4410-a59c-5e113e629f11': {
330
+            'name':'vmware.host_password',
331
+            'value':'password',
332
+            'help': 'VMWare vcenter password',
333
+            'default':'',
334
+            'type':'String',
335
+            'required':True,
336
+            'secret': True,
337
+            'file':'/etc/nova/nova.conf',
338
+            'service_worker_id': '65dbd695-fa92-4950-b8b4-d46aa0408f6a'
339
+        },
340
+    }
341
+]
342
+
343
+
344
+def inject_id(value):
345
+    if isinstance(value, dict):
346
+        _id = value.keys()[0]
347
+        value1 = value[_id].copy()
348
+        value1['id'] = _id
349
+
350
+        return value1
351
+    return value
352
+
353
+
354
+def _device_populate_demo_data():
355
+    for region in REGION_LIST:
356
+        region = inject_id(region)
357
+        api.region_create(None, region)
358
+
359
+    for device in DEVICE_LIST:
360
+        device = inject_id(device)
361
+        api.device_create(None, device)
362
+
363
+    for device_endpoint in ENDPOINT_LIST:
364
+        device_endpoint = inject_id(device_endpoint)
365
+        api.device_endpoint_create(None, device_endpoint)
366
+
367
+    # TODO(kanagaraj-manickam) Move this to alembic upgrade
368
+    for device_driver_class in DEVICE_DRIVER_CLASS_LIST:
369
+        device_driver_class = inject_id(device_driver_class)
370
+        api.device_driver_class_create(None, device_driver_class)
371
+
372
+    for device_driver in DEVICE_DRIVER_LIST:
373
+        device_driver = inject_id(device_driver)
374
+        api.device_driver_create(None, device_driver)
375
+
376
+
377
+def _service_populate_demo_data():
378
+    for service in SERVICE_LIST:
379
+        service = inject_id(service)
380
+        api.service_create(None, service)
381
+
382
+    for service_node in SERVICE_NODE_LIST:
383
+        service_node = inject_id(service_node)
384
+        api.service_node_create(None, service_node)
385
+
386
+    for service_component in SERVICE_COMPONENT_LIST:
387
+        service_component = inject_id(service_component)
388
+        api.service_component_create(None, service_component)
389
+
390
+    for service_worker in SERVICE_WORKER_LIST:
391
+        service_worker = inject_id(service_worker)
392
+        api.service_worker_create(None, service_worker)
393
+
394
+    for config in CONFIG_LIST:
395
+        config = inject_id(config)
396
+        api.config_create(None, config)
397
+
398
+
399
+def populate_demo_data():
400
+    _device_populate_demo_data()
401
+    _service_populate_demo_data()
402
+
403
+
404
+def _device_purge_demo_data():
405
+    for device_driver in DEVICE_DRIVER_LIST:
406
+        api.device_driver_delete(None, device_driver.keys()[0])
407
+
408
+    for device_endpoint in ENDPOINT_LIST:
409
+        api.device_endpoint_delete(None, device_endpoint.keys()[0])
410
+
411
+    # Reverse the order of delete from child to parent device
412
+    for device in DEVICE_LIST[::-1]:
413
+        api.device_delete(None, device.keys()[0])
414
+
415
+    # TODO(kanagaraj-manickam) Move this to alembic downgrade
416
+    for device_driver_class in DEVICE_DRIVER_CLASS_LIST:
417
+        api.device_driver_class_delete(None, device_driver_class.keys()[0])
418
+
419
+
420
+def _service_purge_demo_data():
421
+    for config in CONFIG_LIST:
422
+        api.config_delete(None, config.keys()[0])
423
+    for service_worker in SERVICE_WORKER_LIST:
424
+        api.service_worker_delete(None, service_worker.keys()[0])
425
+
426
+    for service_component in SERVICE_COMPONENT_LIST:
427
+        api.service_component_delete(None, service_component.keys()[0])
428
+
429
+    for service_node in SERVICE_NODE_LIST:
430
+        api.service_node_delete(None, service_node.keys()[0])
431
+
432
+    for service in SERVICE_LIST:
433
+        api.service_delete(None, service.keys()[0])
434
+
435
+
436
+def _region_purge_demo_data():
437
+    for region in REGION_LIST:
438
+        api.region_delete(None, region.keys()[0])
439
+
440
+
441
+def purge_demo_data():
442
+    _service_purge_demo_data()
443
+    _device_purge_demo_data()
444
+    _region_purge_demo_data()

+ 0
- 0
namos/db/sqlalchemy/__init__.py View File


+ 59
- 0
namos/db/sqlalchemy/alembic.ini View File

@@ -0,0 +1,59 @@
1
+# A generic, single database configuration.
2
+
3
+[alembic]
4
+# path to migration scripts
5
+script_location = %(here)s/alembic
6
+
7
+# template used to generate migration files
8
+# file_template = %%(rev)s_%%(slug)s
9
+
10
+# max length of characters to apply to the
11
+# "slug" field
12
+#truncate_slug_length = 40
13
+
14
+# set to 'true' to run the environment during
15
+# the 'revision' command, regardless of autogenerate
16
+# revision_environment = false
17
+
18
+# set to 'true' to allow .pyc and .pyo files without
19
+# a source .py file to be detected as revisions in the
20
+# versions/ directory
21
+# sourceless = false
22
+
23
+#sqlalchemy.url = driver://user:pass@localhost/dbname
24
+#sqlalchemy.url = mysql+mysqldb://root:password@localhost/namos
25
+
26
+# Logging configuration
27
+[loggers]
28
+keys = root,sqlalchemy,alembic
29
+
30
+[handlers]
31
+keys = console
32
+
33
+[formatters]
34
+keys = generic
35
+
36
+[logger_root]
37
+level = WARN
38
+handlers = console
39
+qualname =
40
+
41
+[logger_sqlalchemy]
42
+level = WARN
43
+handlers =
44
+qualname = sqlalchemy.engine
45
+
46
+[logger_alembic]
47
+level = INFO
48
+handlers =
49
+qualname = alembic
50
+
51
+[handler_console]
52
+class = StreamHandler
53
+args = (sys.stderr,)
54
+level = NOTSET
55
+formatter = generic
56
+
57
+[formatter_generic]
58
+format = %(levelname)-5.5s [%(name)s] %(message)s
59
+datefmt = %H:%M:%S

+ 89
- 0
namos/db/sqlalchemy/alembic/env.py View File

@@ -0,0 +1,89 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+from __future__ import with_statement
16
+from alembic import context
17
+from sqlalchemy import engine_from_config, pool
18
+from logging.config import fileConfig
19
+
20
+# this is the Alembic Config object, which provides
21
+# access to the values within the .ini file in use.
22
+config = context.config
23
+
24
+# Interpret the config file for Python logging.
25
+# This line sets up loggers basically.
26
+fileConfig(config.config_file_name)
27
+
28
+# add your model's MetaData object here
29
+# for 'autogenerate' support
30
+# from myapp import mymodel
31
+# target_metadata = mymodel.Base.metadata
32
+
33
+from namos.db.sqlalchemy.models import BASE
34
+target_metadata = BASE.metadata
35
+
36
+# other values from the config, defined by the needs of env.py,
37
+# can be acquired:
38
+# my_important_option = config.get_main_option("my_important_option")
39
+# ... etc.
40
+
41
+
42
+def run_migrations_offline():
43
+    """Run migrations in 'offline' mode.
44
+
45
+    This configures the context with just a URL
46
+    and not an Engine, though an Engine is acceptable
47
+    here as well.  By skipping the Engine creation
48
+    we don't even need a DBAPI to be available.
49
+
50
+    Calls to context.execute() here emit the given string to the
51
+    script output.
52
+
53
+    """
54
+    url = config.get_main_option("sqlalchemy.url")
55
+    context.configure(url=url, target_metadata=target_metadata)
56
+
57
+    with context.begin_transaction():
58
+        context.run_migrations()
59
+
60
+
61
+def run_migrations_online():
62
+    """Run migrations in 'online' mode.
63
+
64
+    In this scenario we need to create an Engine
65
+    and associate a connection with the context.
66
+
67
+    """
68
+    engine = engine_from_config(
69
+        config.get_section(config.config_ini_section),
70
+        prefix='sqlalchemy.',
71
+        poolclass=pool.NullPool)
72
+
73
+    connection = engine.connect()
74
+    context.configure(
75
+        connection=connection,
76
+        target_metadata=target_metadata
77
+        )
78
+
79
+    try:
80
+        with context.begin_transaction():
81
+            context.run_migrations()
82
+    finally:
83
+        connection.close()
84
+
85
+
86
+if context.is_offline_mode():
87
+    run_migrations_offline()
88
+else:
89
+    run_migrations_online()

+ 22
- 0
namos/db/sqlalchemy/alembic/script.py.mako View File

@@ -0,0 +1,22 @@
1
+"""${message}
2
+
3
+Revision ID: ${up_revision}
4
+Revises: ${down_revision}
5
+Create Date: ${create_date}
6
+
7
+"""
8
+
9
+# revision identifiers, used by Alembic.
10
+revision = ${repr(up_revision)}
11
+down_revision = ${repr(down_revision)}
12
+
13
+from alembic import op
14
+import sqlalchemy as sa
15
+${imports if imports else ""}
16
+
17
+def upgrade():
18
+    ${upgrades if upgrades else "pass"}
19
+
20
+
21
+def downgrade():
22
+    ${downgrades if downgrades else "pass"}

+ 188
- 0
namos/db/sqlalchemy/alembic/versions/48ebec3cd6f6_initial_version.py View File

@@ -0,0 +1,188 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+"""Initial version
16
+
17
+Revision ID: 48ebec3cd6f6
18
+Revises: None
19
+Create Date: 2014-10-31 10:57:41.695077
20
+
21
+"""
22
+
23
+# revision identifiers, used by Alembic.
24
+revision = '48ebec3cd6f6'
25
+down_revision = None
26
+
27
+from alembic import op
28
+import sqlalchemy as sa
29
+
30
+
31
+def upgrade():
32
+    op.create_table(
33
+        'service',
34
+        sa.Column('created_at', sa.DateTime(), nullable=True),
35
+        sa.Column('updated_at', sa.DateTime(), nullable=True),
36
+        sa.Column('id', sa.Uuid(length=36), nullable=False),
37
+        sa.Column('name', sa.String(length=255), nullable=False),
38
+        sa.Column('deleted_at', sa.DateTime(), nullable=True),
39
+        sa.Column('extra', sa.Json(), nullable=True),
40
+        sa.Column('keystone_service_id', sa.Uuid(length=36), nullable=False),
41
+        sa.PrimaryKeyConstraint('id'),
42
+        mysql_engine='InnoDB'
43
+        )
44
+
45
+    op.create_table(
46
+        'device_driver_class',
47
+        sa.Column('created_at', sa.DateTime(), nullable=True),
48
+        sa.Column('updated_at', sa.DateTime(), nullable=True),
49
+        sa.Column('id', sa.Uuid(length=36), nullable=False),
50
+        sa.Column('name', sa.String(length=255), nullable=False),
51
+        sa.Column('deleted_at', sa.DateTime(), nullable=True),
52
+        sa.Column('extra', sa.Json(), nullable=True),
53
+        sa.Column('python_class', sa.String(length=64), nullable=False),
54
+        sa.Column('version', sa.String(length=64), nullable=True),
55
+        sa.Column('type', sa.String(length=64), nullable=False),
56
+        sa.PrimaryKeyConstraint('id'),
57
+        mysql_engine='InnoDB'
58
+        )
59
+
60
+    op.create_table(
61
+        'region',
62
+        sa.Column('created_at', sa.DateTime(), nullable=True),
63
+        sa.Column('updated_at', sa.DateTime(), nullable=True),
64
+        sa.Column('id', sa.Uuid(length=36), nullable=False),
65
+        sa.Column('name', sa.String(length=255), nullable=False),
66
+        sa.Column('deleted_at', sa.DateTime(), nullable=True),
67
+        sa.Column('extra', sa.Json(), nullable=True),
68
+        sa.Column('keystone_region_id', sa.String(length=255), nullable=False),
69
+        sa.PrimaryKeyConstraint('id'),
70
+        mysql_engine='InnoDB'
71
+        )
72
+
73
+    op.create_table(
74
+        'device',
75
+        sa.Column('created_at', sa.DateTime(), nullable=True),
76
+        sa.Column('updated_at', sa.DateTime(), nullable=True),
77
+        sa.Column('id', sa.Uuid(length=36), nullable=False),
78
+        sa.Column('name', sa.String(length=255), nullable=False),
79
+        sa.Column('deleted_at', sa.DateTime(), nullable=True),
80
+        sa.Column('status', sa.String(length=64), nullable=False),
81
+        sa.Column('description', sa.Text(), nullable=True),
82
+        sa.Column('extra', sa.Json(), nullable=True),
83
+        sa.Column('display_name', sa.String(length=255), nullable=True),
84
+        sa.Column('parent_id', sa.Uuid(length=36), nullable=True),
85
+        sa.Column('region_id', sa.Uuid(length=36), nullable=False),
86
+        sa.ForeignKeyConstraint(['parent_id'], ['device.id'], ),
87
+        sa.ForeignKeyConstraint(['region_id'], ['region.id'], ),
88
+        sa.PrimaryKeyConstraint('id'),
89
+        mysql_engine='InnoDB'
90
+        )
91
+
92
+    op.create_table(
93
+        'service_node',
94
+        sa.Column('created_at', sa.DateTime(), nullable=True),
95
+        sa.Column('updated_at', sa.DateTime(), nullable=True),
96
+        sa.Column('id', sa.Uuid(length=36), nullable=False),
97
+        sa.Column('name', sa.String(length=255), nullable=False),
98
+        sa.Column('deleted_at', sa.DateTime(), nullable=True),
99
+        sa.Column('description', sa.Text(), nullable=True),
100
+        sa.Column('extra', sa.Json(), nullable=True),
101
+        sa.Column('fqdn', sa.String(length=128), nullable=False),
102
+        sa.Column('region_id', sa.Uuid(length=36), nullable=True),
103
+        sa.ForeignKeyConstraint(['region_id'], ['region.id'], ),
104
+        sa.PrimaryKeyConstraint('id'),
105
+        mysql_engine='InnoDB'
106
+        )
107
+
108
+    op.create_table(
109
+        'device_endpoint',
110
+        sa.Column('created_at', sa.DateTime(), nullable=True),
111
+        sa.Column('updated_at', sa.DateTime(), nullable=True),
112
+        sa.Column('id', sa.Uuid(length=36), nullable=False),
113
+        sa.Column('name', sa.String(length=255), nullable=False),
114
+        sa.Column('extra', sa.Json(), nullable=True),
115
+        sa.Column('device_id', sa.Uuid(length=36), nullable=True),
116
+        sa.Column('connection', sa.Json(), nullable=False),
117
+        sa.ForeignKeyConstraint(['device_id'], ['device.id'], ),
118
+        sa.PrimaryKeyConstraint('id'),
119
+        mysql_engine='InnoDB'
120
+        )
121
+
122
+    op.create_table(
123
+        'service_component',
124
+        sa.Column('created_at', sa.DateTime(), nullable=True),
125
+        sa.Column('updated_at', sa.DateTime(), nullable=True),
126
+        sa.Column('id', sa.Uuid(length=36), nullable=False),
127
+        sa.Column('name', sa.String(length=255), nullable=False),
128
+        sa.Column('deleted_at', sa.DateTime(), nullable=True),
129
+        sa.Column('description', sa.Text(), nullable=True),
130
+        sa.Column('extra', sa.Json(), nullable=True),
131
+        sa.Column('node_id', sa.Uuid(length=36), nullable=False),
132
+        sa.Column('service_id', sa.Uuid(length=36), nullable=False),
133
+        sa.ForeignKeyConstraint(['node_id'], ['service_node.id'], ),
134
+        sa.ForeignKeyConstraint(['service_id'], ['service.id'], ),
135
+        sa.PrimaryKeyConstraint('id'),
136
+        mysql_engine='InnoDB'
137
+        )
138
+
139
+    op.create_table(
140
+        'device_driver',
141
+        sa.Column('created_at', sa.DateTime(), nullable=True),
142
+        sa.Column('updated_at', sa.DateTime(), nullable=True),
143
+        sa.Column('id', sa.Uuid(length=36), nullable=False),
144
+        sa.Column('name', sa.String(length=255), nullable=False),
145
+        sa.Column('deleted_at', sa.DateTime(), nullable=True),
146
+        sa.Column('extra', sa.Json(), nullable=True),
147
+        sa.Column('endpoint_id', sa.Uuid(length=36), nullable=True),
148
+        sa.Column('device_id', sa.Uuid(length=36), nullable=True),
149
+        sa.Column('python_class_id', sa.Uuid(length=36), nullable=True),
150
+        sa.ForeignKeyConstraint(['device_id'], ['device.id'], ),
151
+        sa.ForeignKeyConstraint(['endpoint_id'], ['device_endpoint.id'], ),
152
+        sa.ForeignKeyConstraint(['python_class_id'],
153
+                                ['device_driver_class.id'], ),
154
+        sa.PrimaryKeyConstraint('id'),
155
+        mysql_engine='InnoDB'
156
+        )
157
+
158
+    op.create_table(
159
+        'service_worker',
160
+        sa.Column('created_at', sa.DateTime(), nullable=True),
161
+        sa.Column('updated_at', sa.DateTime(), nullable=True),
162
+        sa.Column('id', sa.Uuid(length=36), nullable=False),
163
+        sa.Column('name', sa.String(length=255), nullable=False),
164
+        sa.Column('deleted_at', sa.DateTime(), nullable=True),
165
+        sa.Column('extra', sa.Json(), nullable=True),
166
+        sa.Column('pid', sa.String(length=32), nullable=False),
167
+        sa.Column('host', sa.String(length=248), nullable=False),
168
+        sa.Column('service_component_id', sa.Uuid(length=36), nullable=False),
169
+        sa.Column('device_driver_id', sa.Uuid(length=36), nullable=False),
170
+        sa.ForeignKeyConstraint(['device_driver_id'], ['device_driver.id'], ),
171
+        sa.ForeignKeyConstraint(['service_component_id'],
172
+                                ['service_component.id'], ),
173
+        sa.PrimaryKeyConstraint('id'),
174
+        mysql_engine='InnoDB'
175
+        )
176
+
177
+
178
+def downgrade():
179
+    op.drop_table('oslo_config')
180
+    op.drop_table('device_driver')
181
+    op.drop_table('service_worker')
182
+    op.drop_table('service_component')
183
+    op.drop_table('device_endpoint')
184
+    op.drop_table('service_node')
185
+    op.drop_table('device')
186
+    op.drop_table('region')
187
+    op.drop_table('device_driver_class')
188
+    op.drop_table('service')

+ 794
- 0
namos/db/sqlalchemy/api.py View File

@@ -0,0 +1,794 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+
16
+import sys
17
+
18
+from oslo_config import cfg
19
+from oslo_db.sqlalchemy import session as db_session
20
+
21
+from namos.common import exception
22
+from namos.db.sqlalchemy import models
23
+
24
+
25
+CONF = cfg.CONF
26
+
27
+_facade = None
28
+
29
+
30
+def get_facade():
31
+    global _facade
32
+
33
+    if not _facade:
34
+        _facade = db_session.EngineFacade.from_config(CONF)
35
+    return _facade
36
+
37
+
38
+get_engine = lambda: get_facade().get_engine()
39
+get_session = lambda: get_facade().get_session()
40
+
41
+
42
+def get_backend():
43
+    """The backend is this module itself."""
44
+    return sys.modules[__name__]
45
+
46
+
47
+def _model_query(context, *args):
48
+    session = _session(context)
49
+    query = session.query(*args)
50
+    return query
51
+
52
+
53
+def _session(context):
54
+    return (context and hasattr(context, 'session') and context.session) \
55
+        or get_session()
56
+
57
+
58
+def _create(context, resource_ref, values):
59
+    resource_ref.update(values)
60
+    resource_ref.save(_session(context))
61
+    return resource_ref
62
+
63
+
64
+def _update(context, cls, _id, values):
65
+    resource_ref = _get(context, cls, _id)
66
+    resource_ref.update_and_save(values, _session(context))
67
+    return resource_ref
68
+
69
+
70
+def _get(context, cls, _id):
71
+    result = _model_query(context, cls).get(_id)
72
+    return result
73
+
74
+
75
+def _get_by_name(context, cls, name):
76
+    result = _model_query(context, cls). \
77
+        filter_by(name=name).first()
78
+    return result
79
+
80
+
81
+# TODO(kanagaraj-manickam): Add pagination
82
+def _get_all(context, cls):
83
+    results = _model_query(context, cls).all()
84
+
85
+    if results is None:
86
+        results = []
87
+
88
+    return results
89
+
90
+
91
+def _get_all_by(context, cls, **kwargs):
92
+    results = _model_query(context, cls).filter_by(**kwargs).all()
93
+    return results
94
+
95
+
96
+def _delete(context, cls, _id):
97
+    result = _get(context, cls, _id)
98
+    if result is not None:
99
+        result.delete(_session(context))
100
+
101
+
102
+# Region
103
+
104
+def region_create(context, values):
105
+    return _create(context, models.Region(), values)
106
+
107
+
108
+def region_update(context, _id, values):
109
+    return _update(context, models.Region, _id, values)
110
+
111
+
112
+def region_get(context, _id):
113
+    region = _get(context, models.Region, _id)
114
+    if region is None:
115
+        raise exception.RegionNotFound(region_id=_id)
116
+
117
+    return region
118
+
119
+
120
+def region_get_by_name(context, name):
121
+    region = _get_by_name(context, models.Region, name)
122
+    if region is None:
123
+        raise exception.RegionNotFound(region_id=name)
124
+
125
+    return region
126
+
127
+
128
+def region_get_all(context):
129
+    return _get_all(context, models.Region)
130
+
131
+
132
+def region_delete(context, _id):
133
+    return _delete(context, models.Region, _id)
134
+
135
+
136
+# Device
137
+
138
+def device_create(context, values):
139
+    return _create(context, models.Device(), values)
140
+
141
+
142
+def device_update(context, _id, values):
143
+    return _update(context, models.Device, _id, values)
144
+
145
+
146
+def device_get(context, _id):
147
+    region = _get(context, models.Device, _id)
148
+    if region is None:
149
+        raise exception.DeviceNotFound(device_id=_id)
150
+
151
+    return region
152
+
153
+
154
+def device_get_by_name(context, name):
155
+    region = _get_by_name(context, models.Device, name)
156
+    if region is None:
157
+        raise exception.DeviceNotFound(device_id=name)
158
+
159
+    return region
160
+
161
+
162
+def device_get_all(context):
163
+    return _get_all(context, models.Device)
164
+
165
+
166
+def _device_get_all_by(context, **kwargs):
167
+    return _get_all_by(context, models.Device, **kwargs)
168
+
169
+
170
+def device_delete(context, _id):
171
+    return _delete(context, models.Device, _id)
172
+
173
+
174
+# Device Endpoint
175
+
176
+def device_endpoint_create(context, values):
177
+    return _create(context, models.DeviceEndpoint(), values)
178
+
179
+
180
+def device_endpoint_update(context, _id, values):
181
+    return _update(context, models.DeviceEndpoint, _id, values)
182
+
183
+
184
+def device_endpoint_get(context, _id):
185
+    region = _get(context, models.DeviceEndpoint, _id)
186
+    if region is None:
187
+        raise exception.DeviceEndpointNotFound(device_endpoint_id=_id)
188
+
189
+    return region
190
+
191
+
192
+def device_endpoint_get_by_name(context, name):
193
+    region = _get_by_name(context, models.DeviceEndpoint, name)
194
+    if region is None:
195
+        raise exception.DeviceEndpointNotFound(device_endpoint_id=name)
196
+
197
+    return region
198
+
199
+
200
+def device_endpoint_get_by_device_type(context,
201
+                                       device_id,
202
+                                       type=None,
203
+                                       name=None):
204
+    query = _model_query(context, models.DeviceEndpoint)
205
+    if device_id is not None:
206
+        query = query.filter_by(device_id=device_id)
207
+    if type is not None:
208
+        query = query.filter_by(type=type)
209
+    if name is not None:
210
+        query = query.filter_by(name=name)
211
+    return query.all()
212
+
213
+
214
+def device_endpoint_get_all(context):
215
+    return _get_all(context, models.DeviceEndpoint)
216
+
217
+
218
+def _device_endpoint_get_all_by(context, **kwargs):
219
+    return _get_all_by(context, models.DeviceEndpoint, **kwargs)
220
+
221
+
222
+def device_endpoint_delete(context, _id):
223
+    return _delete(context, models.DeviceEndpoint, _id)
224
+
225
+
226
+# Device Driver
227
+def device_driver_create(context, values):
228
+    return _create(context, models.DeviceDriver(), values)
229
+
230
+
231
+def device_driver_update(context, _id, values):
232
+    return _update(context, models.DeviceDriver, _id, values)
233
+
234
+
235
+def device_driver_get(context, _id):
236
+    region = _get(context, models.DeviceDriver, _id)
237
+    if region is None:
238
+        raise exception.DeviceDriverNotFound(device_driver_id=_id)
239
+
240
+    return region
241
+
242
+
243
+def device_driver_get_by_name(context, name):
244
+    region = _get_by_name(context, models.DeviceDriver, name)
245
+    if region is None:
246
+        raise exception.DeviceDriverNotFound(device_driver_id=name)
247
+
248
+    return region
249
+
250
+
251
+def device_driver_get_by_device_endpoint_service_worker(
252
+        context,
253
+        device_id=None,
254
+        endpoint_id=None,
255
+        device_driver_class_id=None,
256
+        service_worker_id=None):
257
+    query = _model_query(context, models.DeviceDriver)
258
+    if device_id is not None:
259
+        query = query.filter_by(device_id=device_id)
260
+    if endpoint_id is not None:
261
+        query = query.filter_by(endpoint_id=endpoint_id)
262
+    if device_driver_class_id is not None:
263
+        query = query.filter_by(device_driver_class_id=device_driver_class_id)
264
+    if service_worker_id is not None:
265
+        query = query.filter_by(service_worker_id=service_worker_id)
266
+    return query.all()
267
+
268
+
269
+def device_driver_get_all(context):
270
+    return _get_all(context, models.DeviceDriver)
271
+
272
+
273
+def _device_driver_get_all_by(context, **kwargs):
274
+    return _get_all_by(context, models.DeviceDriver, **kwargs)
275
+
276
+
277
+def device_driver_delete(context, _id):
278
+    return _delete(context, models.DeviceDriver, _id)
279
+
280
+
281
+# Device Driver Class
282
+
283
+def device_driver_class_create(context, values):
284
+    return _create(context, models.DeviceDriverClass(), values)
285
+
286
+
287
+def device_driver_class_update(context, _id, values):
288
+    return _update(context, models.DeviceDriverClass, _id, values)
289
+
290
+
291
+def device_driver_class_get(context, _id):
292
+    region = _get(context, models.DeviceDriverClass, _id)
293
+    if region is None:
294
+        raise exception.DeviceDriverClassNotFound(device_driver_id=_id)
295
+
296
+    return region
297
+
298
+
299
+def device_driver_class_get_by_name(context, name):
300
+    region = _get_by_name(context, models.DeviceDriverClass, name)
301
+    if region is None:
302
+        raise exception.DeviceDriverClassNotFound(device_driver_class_id=name)
303
+
304
+    return region
305
+
306
+
307
+def device_driver_class_get_all(context):
308
+    return _get_all(context, models.DeviceDriverClass)
309
+
310
+
311
+def _device_driver_classget_all_by(context, **kwargs):
312
+    return _get_all_by(context, models.DeviceDriverClass, **kwargs)
313
+
314
+
315
+def device_driver_class_delete(context, _id):
316
+    return _delete(context, models.DeviceDriverClass, _id)
317
+
318
+
319
+# Service
320
+
321
+def service_create(context, values):
322
+    return _create(context, models.Service(), values)
323
+
324
+
325
+def service_update(context, _id, values):
326
+    return _update(context, models.Service, _id, values)
327
+
328
+
329
+def service_get(context, _id):
330
+    region = _get(context, models.Service, _id)
331
+    if region is None:
332
+        raise exception.ServiceNotFound(service_id=_id)
333
+
334
+    return region
335
+
336
+
337
+def service_get_by_name(context, name):
338
+    region = _get_by_name(context, models.Service, name)
339
+    if region is None:
340
+        raise exception.ServiceNotFound(service_id=name)
341
+
342
+    return region
343
+
344
+
345
+def service_get_all(context):
346
+    return _get_all(context, models.Service)
347
+
348
+
349
+def _service_get_all_by(context, **kwargs):
350
+    return _get_all_by(context, models.Service, **kwargs)
351
+
352
+
353
+def service_delete(context, _id):
354
+    return _delete(context, models.Service, _id)
355
+
356
+
357
+# ServiceNode
358
+
359
+def service_node_create(context, values):
360
+    return _create(context, models.ServiceNode(), values)
361
+
362
+
363
+def service_node_update(context, _id, values):
364
+    return _update(context, models.ServiceNode, _id, values)
365
+
366
+
367
+def service_node_get(context, _id):
368
+    region = _get(context, models.ServiceNode, _id)
369
+    if region is None:
370
+        raise exception.ServiceNodeNotFound(service_node_id=_id)
371
+
372
+    return region
373
+
374
+
375
+def service_node_get_by_name(context, name):
376
+    region = _get_by_name(context, models.ServiceNode, name)
377
+    if region is None:
378
+        raise exception.ServiceNodeNotFound(service_node_id=name)
379
+
380
+    return region
381
+
382
+
383
+def service_node_get_all(context):
384
+    return _get_all(context, models.ServiceNode)
385
+
386
+
387
+def _service_node_get_all_by(context, **kwargs):
388
+    return _get_all_by(context, models.ServiceNode, **kwargs)
389
+
390
+
391
+def service_node_delete(context, _id):
392
+    return _delete(context, models.ServiceNode, _id)
393
+
394
+
395
+# ServiceComponent
396
+
397
+def service_component_create(context, values):
398
+    return _create(context, models.ServiceComponent(), values)
399
+
400
+
401
+def service_component_update(context, _id, values):
402
+    return _update(context, models.ServiceComponent, _id, values)
403
+
404
+
405
+def service_component_get(context, _id):
406
+    region = _get(context, models.ServiceComponent, _id)
407
+    if region is None:
408
+        raise exception.ServiceComponentNotFound(service_component_id=_id)
409
+
410
+    return region
411
+
412
+
413
+def service_component_get_by_name(context, name):
414
+    region = _get_by_name(context, models.ServiceComponent, name)
415
+    if region is None:
416
+        raise exception.ServiceComponentNotFound(service_component_id=name)
417
+
418
+    return region
419
+
420
+
421
+def service_component_get_all_by_node_for_service(context,
422
+                                                  node_id,
423
+                                                  service_id=None,
424
+                                                  name=None):
425
+    query = _model_query(context, models.ServiceComponent). \
426
+        filter_by(node_id=node_id)
427
+    if service_id is not None:
428
+        query = query.filter_by(service_id=service_id)
429
+    if name is not None:
430
+        query = query.filter_by(name=name)
431
+    return query.all()
432
+
433
+
434
+def service_component_get_all(context):
435
+    return _get_all(context, models.ServiceComponent)
436
+
437
+
438
+def _service_component_get_all_by(context, **kwargs):
439
+    return _get_all_by(context, models.ServiceComponent, **kwargs)
440
+
441
+
442
+def service_component_delete(context, _id):
443
+    return _delete(context, models.ServiceComponent, _id)
444
+
445
+
446
+# ServiceWorker
447
+
448
+def service_worker_create(context, values):
449
+    return _create(context, models.ServiceWorker(), values)
450
+
451
+
452
+def service_worker_update(context, _id, values):
453
+    return _update(context, models.ServiceWorker, _id, values)
454
+
455
+
456
+def service_worker_get(context, _id):
457
+    service_worker = _get(context, models.ServiceWorker, _id)
458
+    if service_worker is None:
459
+        raise exception.ServiceWorkerNotFound(service_worker_id=_id)
460
+
461
+    return service_worker
462
+
463
+
464
+def service_worker_get_by_name(context, name):
465
+    service_worker = _get_by_name(context, models.ServiceWorker, name)
466
+    if service_worker is None:
467
+        raise exception.ServiceWorkerNotFound(service_worker_id=name)
468
+
469
+    return service_worker
470
+
471
+
472
+def service_worker_get_by_host_for_service_component(context,
473
+                                                     service_component_id,
474
+                                                     host=None):
475
+    query = _model_query(context, models.ServiceWorker). \
476
+        filter_by(service_component_id=service_component_id)
477
+    if host is not None:
478
+        query = query.filter_by(host=host)
479
+    return query.all()
480
+
481
+
482
+def service_worker_get_all(context):
483
+    return _get_all(context, models.ServiceWorker)
484
+
485
+
486
+def _service_worker_get_all_by(context, **kwargs):
487
+    return _get_all_by(context, models.ServiceWorker, **kwargs)
488
+
489
+
490
+def service_worker_delete(context, _id):
491
+    return _delete(context, models.ServiceWorker, _id)
492
+
493
+
494
+# Config
495
+
496
+def config_create(context, values):
497
+    return _create(context, models.OsloConfig(), values)
498
+
499
+
500
+def config_update(context, _id, values):
501
+    return _update(context, models.OsloConfig, _id, values)
502
+
503
+
504
+def config_get(context, _id):
505
+    config = _get(context, models.OsloConfig, _id)
506
+    if config is None:
507
+        raise exception.ConfigNotFound(config_id=_id)
508
+
509
+    return config
510
+
511
+
512
+def config_get_by_name(context, name):
513
+    config = _get_by_name(context, models.OsloConfig, name)
514
+    if config is None:
515
+        raise exception.ConfigNotFound(config_id=name)
516
+
517
+    return config
518
+
519
+
520
+def config_get_by_name_for_service_worker(context,
521
+                                          service_worker_id,
522
+                                          name=None):
523
+    query = _model_query(context, models.OsloConfig). \
524
+        filter_by(service_worker_id=service_worker_id)
525
+    if name is not None:
526
+        query = query.filter_by(name=name)
527
+    return query.all()
528
+
529
+
530
+def config_get_all(context):
531
+    return _get_all(context, models.OsloConfig)
532
+
533
+
534
+def _config_get_all_by(context, **kwargs):
535
+    return _get_all_by(context, models.OsloConfig, **kwargs)
536
+
537
+
538
+def config_delete(context, _id):
539
+    return _delete(context, models.OsloConfig, _id)
540
+
541
+
542
+# REST-API
543
+def service_perspective_get(context, service_id, include_details=False):
544
+    # 1. itr over Service Components and find name vs set of components
545
+    #      (for example, nova-compute vs set of nova-compute deployment)
546
+    #      Mention the service_node
547
+    # 2. For each components, itr over Service Workers
548
+    # 3. For each workers, itr over device_drivers
549
+    # 4. For each device_driver, Mention
550
+    #               device_driver_class
551
+    #               device_endpoint<->device
552
+
553
+    # on include_details, for each of the entity, include complete details
554
+    service_perspective = dict()
555
+    service_perspective['service'] = service_get(context, service_id).to_dict()
556
+    service_components = _service_component_get_all_by(context,
557
+                                                       service_id=service_id)
558
+    service_perspective['service_components'] = dict()
559
+    # service_perspective['service_components']['size'] =
560
+    # len(service_components)
561
+
562
+    for sc in service_components:
563
+        service_perspective['service_components'][sc.id] = dict()
564
+        service_perspective['service_components'][sc.id]['service_component']\
565
+            = sc.to_dict()
566
+        service_perspective['service_components'][sc.id]['service_node']\
567
+            = service_node_get(context, sc.node_id).to_dict()
568
+        service_workers = _service_worker_get_all_by(
569
+            context,
570
+            service_component_id=sc.id)
571
+        service_perspective['service_components'][sc.id]['service_workers'] \
572
+            = dict()
573
+        # service_perspective['service_components'][sc.id]\
574
+        # ['service_workers']['size'] = len(service_workers)
575
+
576
+        for sw in service_workers:
577
+            service_perspective['service_components'][
578
+                sc.id]['service_workers'][sw.id] = dict()
579
+            service_perspective['service_components'][
580
+                sc.id]['service_workers'][sw.id][
581
+                'service_worker'] = sw.to_dict()
582
+
583
+            device_drivers = _device_driver_get_all_by(
584
+                context,
585
+                service_worker_id=sw.id)
586
+            service_perspective['service_components'][
587
+                sc.id]['service_workers'][sw.id]['device_drivers'] = dict()
588
+
589
+            # service_perspective['service_components'][sc.id]\
590
+            # ['service_workers'][sw.id]['device_drivers']['size'] \
591
+            #     = len(device_drivers)
592
+            for driver in device_drivers:
593
+                service_perspective['service_components'][
594
+                    sc.id]['service_workers'][sw.id]['device_drivers'][
595
+                    driver.id] = dict()
596
+                service_perspective['service_components'][
597
+                    sc.id]['service_workers'][sw.id]['device_drivers'][
598
+                    driver.id]['driver'] = driver.to_dict()
599
+                service_perspective['service_components'][
600
+                    sc.id]['service_workers'][sw.id]['device_drivers'][
601
+                    driver.id]['device_endpoint'] = device_endpoint_get(
602
+                    context,
603
+                    driver.endpoint_id).to_dict()
604
+                service_perspective['service_components'][
605
+                    sc.id]['service_workers'][sw.id]['device_drivers'][
606
+                    driver.id]['device'] = device_get(
607
+                    context,
608
+                    driver.device_id).to_dict()
609
+                service_perspective['service_components'][
610
+                    sc.id]['service_workers'][sw.id]['device_drivers'][
611
+                    driver.id][
612
+                    'device_driver_class'] = device_driver_class_get(
613
+                    context,
614
+                    driver.device_driver_class_id
615
+                ).to_dict()
616
+
617
+    return service_perspective
618
+
619
+
620
+# REST-API
621
+def device_perspective_get(context, device_id, include_details=False):
622
+    # 1. list endpoints
623
+    # 2. For each endpoint, itr over device_drivers and
624
+    # find device_driver_class vs set of device_driver (for example,
625
+    # nova-compute-vc-driver vs set of nova-compute's device-driver deployment)
626
+    # 3. For each drivers, mention service_worker,
627
+    #    service_component<->service_node<->service
628
+
629
+    # on include_details, for each of the entity, include complete details
630
+    device_perspective = dict()
631
+    device_perspective['device'] = device_get(context, device_id).to_dict()
632
+    endpoints = _device_endpoint_get_all_by(context,
633
+                                            device_id=device_id)
634
+    device_perspective['device_endpoints'] = dict()
635
+    # device_perspective['device_endpoints']['size'] = len(endpoints)
636
+
637
+    for ep in endpoints:
638
+        device_perspective['device_endpoints'][ep.id] = dict()
639
+        device_perspective['device_endpoints'][
640
+            ep.id]['device_endpoint'] = ep.to_dict()
641
+
642
+        device_drivers = _device_driver_get_all_by(context,
643
+                                                   endpoint_id=ep.id)
644
+        device_perspective['device_endpoints'][
645
+            ep.id]['device_drivers'] = dict()
646
+        # device_perspective['device_endpoints'][ep.id] \
647
+        # ['device_drivers']['size'] = len(device_drivers)
648
+
649
+        for driver in device_drivers:
650
+            device_perspective['device_endpoints'][
651
+                ep.id]['device_drivers'][driver.id] = dict()
652
+            device_perspective['device_endpoints'][
653
+                ep.id]['device_drivers'][driver.id][
654
+                'device_driver'] = driver.to_dict()
655
+
656
+            service_worker = service_worker_get(
657
+                context,
658
+                driver.service_worker_id)
659
+            service_component = service_component_get(
660
+                context,
661
+                service_worker.service_component_id)
662
+            device_perspective['device_endpoints'][
663
+                ep.id]['device_drivers'][
664
+                driver.id]['service_worker'] = service_worker.to_dict()
665
+            service = service_get(context, service_component.service_id)
666
+
667
+            device_perspective['device_endpoints'][
668
+                ep.id]['device_drivers'][
669
+                driver.id]['service_component'] = service_component.to_dict()
670
+
671
+            device_perspective['device_endpoints'][
672
+                ep.id]['device_drivers'][
673
+                driver.id]['service'] = service.to_dict()
674
+            device_perspective['device_endpoints'][
675
+                ep.id]['device_drivers'][driver.id][
676
+                'device_driver_class'] = device_driver_class_get(
677
+                    context,
678
+                    driver.device_driver_class_id
679
+                ).to_dict()
680
+
681
+    return device_perspective
682
+
683
+
684
+# REST-API
685
+def region_perspective_get(context, region_id, include_details=False):
686
+    # itr over service_nodes
687
+    #   For each service_nodes, itr over service_id
688
+    # itr over devices.
689
+
690
+    # on include_details, for each of the entity, include complete details
691
+
692
+    region_perspective = dict()
693
+    region_perspective['region'] = region_get(context, region_id).to_dict()
694
+    s_nodes = _service_node_get_all_by(context,
695
+                                       region_id=region_id)
696
+    # region_perspective['service_nodes'] = dict()
697
+    # region_perspective['service_nodes']['size'] = len(s_nodes)
698
+    # for s_node in s_nodes:
699
+    #     region_perspective['service_nodes'][s_node.id] = dict()
700
+    #     region_perspective['service_nodes'][s_node.id]['service_node']\
701
+    #         = s_node
702
+    #     s_components = _service_component_get_all_by(context,
703
+    #                             node_id=s_node.id)
704
+    #     srvs = list()
705
+    #     for s_component in s_components:
706
+    #         srvs.append(s_component.service_id)
707
+    #     srvs = set(srvs)
708
+    #
709
+    #     region_perspective['service_nodes'][s_node.id]['services'] = dict()
710
+    #     region_perspective['service_nodes'][s_node.id]['services']['size']\
711
+    #         = len(srvs)
712
+    #     for s_id in srvs:
713
+    #         s = service_get(context, s_id)
714
+    #         region_perspective['service_nodes'][s_node.id]['services'][s_id]\
715
+    #             = s
716
+
717
+    region_perspective['services'] = dict()
718
+    for s_node in s_nodes:
719
+        s_components = _service_component_get_all_by(
720
+            context,
721
+            node_id=s_node.id)
722
+        srvs = list()
723
+        for s_component in s_components:
724
+            srvs.append(s_component.service_id)
725
+        srvs = set(srvs)
726
+
727
+        # region_perspective['services']['size']\
728
+        #     = len(srvs)
729
+        for s_id in srvs:
730
+            s = service_get(context, s_id)
731
+            region_perspective['services'][s_id] = s.to_dict()
732
+
733
+    devices = _device_get_all_by(context, region_id=region_id)
734
+    region_perspective['devices'] = dict()
735
+    # region_perspective['devices']['size'] = len(devices)
736
+    for d in devices:
737
+        region_perspective['devices'][d.id] = d.to_dict()
738
+
739
+    return region_perspective
740
+
741
+
742
+def infra_perspective_get(context):
743
+    infra_perspective = dict()
744
+
745
+    regions = region_get_all(context)
746
+    infra_perspective['regions'] = dict()
747
+    # infra_perspective['regions']['size'] = len(regions)
748
+
749
+    for region in regions:
750
+        infra_perspective['regions'][region.id] = dict()
751
+        infra_perspective['regions'][region.id]['region'] = region.to_dict()
752
+        region_perspective = region_perspective_get(context,
753
+                                                    region.id)
754
+
755
+        infra_perspective['regions'][region.id]['services'] = dict()
756
+        for s_id in region_perspective['services']:
757
+            infra_perspective['regions'][
758
+                region.id]['services'][s_id] = service_perspective_get(
759
+                context,
760
+                s_id)
761
+
762
+        infra_perspective['regions'][region.id]['devices'] = dict()
763
+        for d_id in region_perspective['devices']:
764
+            infra_perspective['regions'][region.id]['devices'][
765
+                d_id] = device_perspective_get(
766
+                context,
767
+                d_id)
768
+
769
+    return infra_perspective
770
+
771
+if __name__ == '__main__':
772
+    from namos.common import config
773
+
774
+    config.init_conf(prog='test-run')
775
+    # print config_get_by_name_for_service_worker(
776
+    #     None,
777
+    #     'f46983a4-6b42-48b0-8b66-66175fa07bc8',
778
+    #     'database.use_db_reconnect'
779
+    # )
780
+
781
+    # print region_perspective_get(None,
782
+    #                     region_id='f7dcd175-27ef-46b5-997f-e6e572f320b0')
783
+    #
784
+    # print service_perspective_get(None,
785
+    #                     service_id='11367a37-976f-468a-b8dd-77b28ee63cf4')
786
+    #
787
+    # print device_perspective_get(
788
+    #     None,
789
+    #     device_id='05b935b3-942c-439c-a6a4-9c3c73285430')
790
+
791
+    # persp = infra_perspective_get(None)
792
+    # import json
793
+    # perp_json = json.dumps(persp, indent=4)
794
+    # print perp_json

+ 123
- 0
namos/db/sqlalchemy/migration.py View File

@@ -0,0 +1,123 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+import os
16
+
17
+import alembic
18
+from alembic import config as alembic_config
19
+import alembic.migration as alembic_migration
20
+
21
+from oslo_config import cfg
22
+from oslo_db import exception as db_exc
23
+
24
+from namos.db.sqlalchemy import api as sqla_api
25
+from namos.db.sqlalchemy import models
26
+
27
+
28
+# Following commands are based on sqlalchemy
29
+def version(config=None, engine=None):
30
+    """Current database version.
31
+
32
+    :returns: Database version
33
+    :rtype: string
34
+    """
35
+    if engine is None:
36
+        engine = sqla_api.get_engine()
37
+    with engine.connect() as conn:
38
+        context = alembic_migration.MigrationContext.configure(conn)
39
+        return context.get_current_revision()
40
+
41
+
42
+def create_schema(config=None, engine=None):
43
+    """Create database schema from models description.
44
+
45
+    Can be used for initial installation instead of upgrade('head').
46
+    """
47
+    if engine is None:
48
+        engine = sqla_api.get_engine()
49
+
50
+    if version(engine=engine) is not None:
51
+        raise db_exc.DbMigrationError("DB schema is already under version"
52
+                                      " control. Use upgrade instead")
53
+
54
+    models.BASE.metadata.create_all(engine)
55
+    stamp('head', config=config)
56
+
57
+
58
+# Following commands are alembic commands
59
+
60
+def _alembic_config():
61
+    # TODO(kanagaraj-manickam): It is an hack to use database.connection
62
+    # for all alembic related commands
63
+
64
+    path = os.path.join(os.path.dirname(__file__), 'alembic.ini')
65
+    config = alembic_config.Config(path)
66
+    config.set_main_option('sqlalchemy.url', cfg.CONF.database.connection)
67
+    return config
68
+
69
+
70
+def upgrade(revision, config=None):
71
+    """Used for upgrading database.
72
+
73
+    :param version: Desired database version
74
+    :type version: string
75
+    """
76
+    revision = revision or 'head'
77
+    config = config or _alembic_config()
78
+
79
+    alembic.command.upgrade(config, revision)
80
+
81
+
82
+def downgrade(revision, config=None):
83
+    """Used for downgrading database.
84
+
85
+    :param version: Desired database version
86
+    :type version: string
87
+    """
88
+    revision = revision or 'base'
89
+    config = config or _alembic_config()
90
+    return alembic.command.downgrade(config, revision)
91
+
92
+
93
+def stamp(revision, config=None):
94
+    """Stamps database with provided revision.
95
+
96
+    Don't run any migrations.
97
+
98
+    :param revision: Should match one from repository or head - to stamp
99
+                     database with most recent revision
100
+    :type revision: string
101
+    """
102
+    config = config or _alembic_config()
103
+    return alembic.command.stamp(config, revision=revision)
104
+
105
+
106
+def revision(message=None, autogenerate=False, config=None):
107
+    """Creates template for migration.
108
+
109
+    :param message: Text that will be used for migration title
110
+    :type message: string
111
+    :param autogenerate: If True - generates diff based on current database
112
+                         state
113
+    :type autogenerate: bool
114
+    """
115
+    config = config or _alembic_config()
116
+    return alembic.command.revision(config, message=message,
117
+                                    autogenerate=autogenerate)
118
+
119
+
120
+def history(config=None):
121
+    """List the available versions."""
122
+    config = config or _alembic_config()
123
+    return alembic.command.history(config)

+ 294
- 0
namos/db/sqlalchemy/models.py View File

@@ -0,0 +1,294 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+"""
16
+SQLAlchemy models for namos database
17
+"""
18
+
19
+import sqlalchemy
20
+from sqlalchemy.ext.declarative import declarative_base
21
+import uuid
22
+
23
+from namos.db.sqlalchemy.types import Json
24
+from namos.db.sqlalchemy.types import Uuid
25
+from oslo_db.sqlalchemy import models
26
+from oslo_utils import timeutils
27
+
28
+
29
+BASE = declarative_base()
30
+
31
+
32
+class NamosBase(models.ModelBase,
33
+                models.TimestampMixin):
34
+    # TODO(kanagaraj-manickam) Make this as db independent
35
+    __table_args__ = {'mysql_engine': 'InnoDB'}
36
+
37
+    id = sqlalchemy.Column(Uuid, primary_key=True,
38
+                           default=lambda: str(uuid.uuid4()))
39
+    name = sqlalchemy.Column(sqlalchemy.String(255),
40
+                             # unique=True,
41
+                             nullable=False,
42
+                             default=lambda: str(uuid.uuid4()))
43
+
44
+    def expire(self, session, attrs=None):
45
+        session.expire(self, attrs)
46
+
47
+    def refresh(self, session, attrs=None):
48
+        session.refresh(self, attrs)
49
+
50
+    def delete(self, session):
51
+        session.delete(self)
52
+        session.flush()
53
+
54
+    def update_and_save(self, values, session):
55
+        self.update(values)
56
+        self.save(session)
57
+
58
+    def __str__(self):
59
+        return "{id:%s, name:%s}" % (self.id, self.name)
60
+
61
+    def __repr__(self):
62
+        return str(self.to_dict())
63
+
64
+    def to_dict(self):
65
+        result = dict()
66
+        for k, v in self.iteritems():
67
+            if not str(k).endswith('_at'):
68
+                result[k] = v
69
+        return result
70
+
71
+
72
+class SoftDelete(object):
73
+    deleted_at = sqlalchemy.Column(sqlalchemy.DateTime)
74
+
75
+    def soft_delete(self, session):
76
+        self.update_and_save({'deleted_at': timeutils.utcnow()},
77
+                             session=session)
78
+
79
+
80
+class StateAware(object):
81
+    status = sqlalchemy.Column(
82
+        'status',
83
+        sqlalchemy.String(64),
84
+        nullable=False)
85
+
86
+
87
+class Description(object):
88
+    description = sqlalchemy.Column(sqlalchemy.Text)
89
+
90
+
91
+class Extra(object):
92
+    extra = sqlalchemy.Column(Json)
93
+
94
+
95
+class Region(BASE,
96
+             NamosBase,
97
+             SoftDelete,
98
+             Extra):
99
+    __tablename__ = 'region'
100
+
101
+    # Its of type String to match with keystone region id
102
+    keystone_region_id = sqlalchemy.Column(
103
+        sqlalchemy.String(255),
104
+        nullable=False)
105
+
106
+
107
+class Device(BASE,
108
+             NamosBase,
109
+             SoftDelete,
110
+             StateAware,
111
+             Description,
112
+             Extra):
113
+    __tablename__ = 'device'
114
+
115
+    display_name = sqlalchemy.Column(sqlalchemy.String(255))
116
+    parent_id = sqlalchemy.Column(
117
+        Uuid,
118
+        sqlalchemy.ForeignKey('device.id'))
119
+    region_id = sqlalchemy.Column(
120
+        Uuid,
121
+        sqlalchemy.ForeignKey('region.id'),
122
+        nullable=False)
123
+    # TODO(kanagaraj-manickam) owner with keystone user id as one field??
124
+
125
+
126
+class DeviceEndpoint(BASE,
127
+                     NamosBase,
128
+                     Extra):
129
+    __tablename__ = 'device_endpoint'
130
+
131
+    device_id = sqlalchemy.Column(
132
+        Uuid,
133
+        sqlalchemy.ForeignKey('device.id'),
134
+        nullable=False)
135
+    type = sqlalchemy.Column(
136
+        sqlalchemy.String(32)
137
+    )
138
+    connection = sqlalchemy.Column(
139
+        Json,
140
+        nullable=False)
141
+
142
+
143
+class DeviceDriver(BASE,
144
+                   NamosBase,
145
+                   SoftDelete,
146
+                   Extra):
147
+    __tablename__ = 'device_driver'
148
+
149
+    endpoint_id = sqlalchemy.Column(
150
+        Uuid,
151
+        sqlalchemy.ForeignKey('device_endpoint.id')
152
+    )
153
+
154
+    device_id = sqlalchemy.Column(
155
+        Uuid,
156
+        sqlalchemy.ForeignKey('device.id'))
157
+
158
+    device_driver_class_id = sqlalchemy.Column(
159
+        Uuid,
160
+        sqlalchemy.ForeignKey('device_driver_class.id')
161
+    )
162
+    service_worker_id = sqlalchemy.Column(
163
+        Uuid,
164
+        sqlalchemy.ForeignKey('service_worker.id')
165
+    )
166
+
167
+# List of supported drivers in a given openstack release. so when
168
+# openstack is released, migration script could be updated to pre-populate
169
+# drivers in this table, which helps to track the drivers being released
170
+# in the given openstack version.
171
+
172
+
173
+class DeviceDriverClass(BASE,
174
+                        NamosBase,
175
+                        SoftDelete,
176
+                        Extra):
177
+    __tablename__ = 'device_driver_class'
178
+
179
+    # TODO(kanagaraj-manickam) Correct the max python class path here
180
+    python_class = sqlalchemy.Column(
181
+        sqlalchemy.String(64),
182
+        nullable=False
183
+    )
184
+    # service type like compute, network, volume, etc
185
+    type = sqlalchemy.Column(
186
+        sqlalchemy.String(64),
187
+        nullable=False
188
+    )
189
+
190
+    # TODO(kanagaraj-manickam) add vendor,
191
+    # additional details like protocol, etc,
192
+    # Capture all related driver details
193
+
194
+
195
+class Service(BASE,
196
+              NamosBase,
197
+              SoftDelete,
198
+              Extra):
199
+    __tablename__ = 'service'
200
+
201
+    keystone_service_id = sqlalchemy.Column(
202
+        Uuid,
203
+        nullable=False)
204
+
205
+
206
+class ServiceNode(BASE,
207
+                  NamosBase,
208
+                  SoftDelete,
209
+                  Description,
210
+                  Extra):
211
+    __tablename__ = 'service_node'
212
+
213
+    fqdn = sqlalchemy.Column(
214
+        sqlalchemy.String(128),
215
+        nullable=False)
216
+    region_id = sqlalchemy.Column(
217
+        Uuid,
218
+        sqlalchemy.ForeignKey('region.id'))
219