2e3e7de26746a853d40e4b88fb36e2694cdb0099
[dcaegen2/platform.git] / oti / event-handler / otihandler / cbs_rest.py
1 # ================================================================================
2 # Copyright (c) 2019-2020 AT&T Intellectual Property. All rights reserved.
3 # ================================================================================
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #      http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 # ============LICENSE_END=========================================================
16
17 """REST for high-level information retrievals from Consul KVs"""
18
19 import copy
20 import logging
21
22 from otihandler.consul_client import ConsulClient
23
24
25 class CBSRest(object):
26     _logger = logging.getLogger("oti_handler.cbs_rest")
27
28     @staticmethod
29     def get_value(key, default=None):
30         """Wrap ConsulClient.get_value() to ignore exceptions."""
31
32         data = default
33         try:
34             data = ConsulClient.get_value(key)
35         except Exception as e:
36             pass
37
38         return data
39
40     @staticmethod
41     def get_kvs(key):
42         """Wrap ConsulClient.get_kvs() to ignore exceptions."""
43
44         data = {}
45         try:
46             data = ConsulClient.get_kvs(key, trim_prefix=True)
47         except Exception as e:
48             data = {}
49
50         if not data:
51             data = {}
52         return data
53
54     @staticmethod
55     def get_service_component(service_name):
56         """Get the fully-bound config for a service_name."""
57
58         return ConsulClient.get_service_component(service_name)
59
60     @staticmethod
61     def get_service_component_all(service_name, service_location=None, policies_as_list=False):
62         """Get all Consul objects for a service_name."""
63
64         r_dict = ConsulClient.get_service_component_all(service_name, policies_as_list=policies_as_list)
65         if r_dict and r_dict.get('oti'):
66             r_dict['oti'] = CBSRest.get_oti(service_name, service_location=service_location)
67         return r_dict
68
69     @staticmethod
70     def get_oti(service_name=None, vnf_type=None, vnf_id=None, service_location=None):
71         """
72         Get DTI events.
73
74         Parameters
75         ----------
76         service_name : string
77             optional.  The service component name assigned by dockerplugin to the component that is unique to the cloudify node instance and used in its Consul key(s).
78         vnf_type : string
79             optional, allows multiple values separated by commas.  Gets DTI events for these vnf_type(s).
80         vnf_id : string
81             optional.  Requires vnf_type also.  Gets DTI event for this vnf_id.
82         service_location : string
83             optional, allows multiple values separated by commas.  Filters DTI events with dcae_service_location in service_location.
84             If service_location is not provided, then defaults to dockerhost or k8s cluster master node service Consul TAGs if service_name is provided,
85             otherwise results are not location filtered.
86
87         Returns
88         -------
89         dict
90             Dictionary of DTI event(s). 
91             If one vnf_type and vnf_id are both specified, then object returned will be just the one DTI event.
92             If one vnf_type is specified but not vnf_id, then DTI events will be keyed by vnf_id.
93             Otherwise the DTI events will be keyed by vnf_type, sub-keyed by vnf_id.
94
95         """
96
97         lc_vnf_type = vnf_type
98         if vnf_type:
99             lc_vnf_type = vnf_type.lower()
100
101         r_dict = {}
102
103         want_locs = []
104         if service_location:
105             want_locs = service_location.split(',')
106
107         give_types = []
108         if service_name:
109             if not want_locs:  # default to TAGs of container's dockerhost or k8s cluster master node
110                try:
111                    node_name = ConsulClient.lookup_service(service_name)[0].get("Node")
112                    if node_name:
113                        services = ConsulClient.lookup_node(node_name).get("Services")
114                        if services:
115                            for node_svc in list(services.keys()):
116                                if "-component-dockerhost-" in node_svc or "_component_kubernetes_master" in node_svc:
117                                    want_locs = services[node_svc].get("Tags", [])
118                                    break
119                except:
120                    pass
121             supported_types = ConsulClient.get_value(service_name + ":oti")
122             if supported_types:
123                 supported_types = [type.lower() for type in list(supported_types.keys())]
124             if supported_types:
125                 if lc_vnf_type:  # If user specifies vnf_type(s), constrain to supported ones
126                     for type in lc_vnf_type.split(','):
127                         if type in supported_types:
128                             give_types.append(type)
129                 else:
130                     give_types = supported_types
131             if not give_types or (len(give_types) == 1 and give_types[0] == ''):
132                 return r_dict
133         elif lc_vnf_type:
134             give_types = lc_vnf_type.split(',')
135
136
137         # If they specified only one vnf_type ...
138         if lc_vnf_type and ',' not in lc_vnf_type:
139             type = give_types[0]
140
141             # ... and vnf_id
142             if vnf_id:
143                 # get just one vnf_id
144                 t_dict = CBSRest.get_value("oti_events/" + type + "/" + vnf_id, default=None)
145                 if t_dict:
146                     event_loc = t_dict.get('dcae_service_location')
147                     if not event_loc or not want_locs or event_loc in want_locs:
148                         r_dict = copy.deepcopy(t_dict)
149
150             # ... and not vnf_id
151             else:
152                 # get all DTI events of just one type, indexed by vnf_id
153                 t_dict = CBSRest.get_kvs("oti_events/" + type + "/")
154                 if t_dict:
155                     if not want_locs:
156                         r_dict = copy.deepcopy(t_dict)
157                     else:
158                         for id in t_dict:
159                             event_loc = t_dict[id].get('dcae_service_location')
160                             if not event_loc or event_loc in want_locs:
161                                 r_dict[id] = copy.deepcopy(t_dict[id])
162
163         # If they did not specify either service_name or vnf_type (the only way give_types=[])
164         elif not give_types:
165             # get all DTI events, indexed by vnf_type then vnf_id
166             t_dict = CBSRest.get_kvs("oti_events/")
167             if t_dict:
168                 for type in t_dict:
169                     for id in t_dict[type]:
170                         if not vnf_id or vnf_id == id:
171                             if want_locs:
172                                 event_loc = t_dict[type][id].get('dcae_service_location')
173                             if not want_locs or not event_loc or event_loc in want_locs:
174                                 if type not in r_dict:
175                                     r_dict[type] = {}
176                                 r_dict[type][id] = copy.deepcopy(t_dict[type][id])
177
178         # If they speclfied multiple vnf_types
179         else:
180             # get all DTI events of give_types, indexed by vnf_type then vnf_id
181             for type in give_types:
182                 t_dict = CBSRest.get_kvs("oti_events/" + type + "/")
183                 if t_dict:
184                     for id in t_dict:
185                         if not vnf_id or vnf_id == id:
186                             if want_locs:
187                                 event_loc = t_dict[id].get('dcae_service_location')
188                             if not want_locs or not event_loc or event_loc in want_locs:
189                                 if type not in r_dict:
190                                     r_dict[type] = {}
191                                 r_dict[type][id] = copy.deepcopy(t_dict[id])
192
193         return r_dict
194
195     @staticmethod
196     def get_policies(service_name, policy_id=None):
197         """Get one or all policies for a service_name."""
198
199         if policy_id:
200             return ConsulClient.get_value(service_name + ":policies/items/" + policy_id)
201         else:
202             return ConsulClient.get_kvs(service_name + ":policies/items/", trim_prefix=True)