3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
17 from cmframework.apis import cmclient
19 from yarf.restresource import RestResource
21 MISSING_LOG_STORE_ENTRY_INDEX = 'Missing log store entry index parameter'
22 PATTERN_SHOULD_BE_ONE_OF = '{} should be one of: {}'
25 NAMESPACE = 'namespace'
26 SUPPORTED_BACKENDS = ('elasticsearch', 'remote_syslog')
27 SUPPORTED_STREAMS = ('stdout', 'stderr', 'both')
30 class CaasHandler(RestResource):
31 KEY_CAAS = 'cloud.caas'
33 def _get_caas_config(self):
34 api = cmclient.CMClient()
35 return json.loads(api.get_property(self.KEY_CAAS))
37 def _update_caas_config(self, updated):
38 api = cmclient.CMClient()
39 api.set_property(self.KEY_CAAS, json.dumps(updated))
42 def _response(return_code, data='', error_desc=''):
43 return {"code": return_code, "description": error_desc, "data": data}
45 def _result(self, data=None):
46 return self._response(0, data=data)
48 def _error(self, exc):
49 error_desc = str(exc).replace('Internal error, ', '')
50 return self._response(1, error_desc=error_desc)
52 def _modify_caas_config(self, modifier_method):
54 caas = self._get_caas_config()
55 modifier_method(self, caas, self.get_args())
56 self._update_caas_config(caas)
57 return self._result('')
58 except Exception as exc:
59 return self._error(exc)
62 class AppLogStoreHandler(CaasHandler):
63 KEY_NAME = 'log_forwarding'
65 parser_arguments = [ID, NAMESPACE, 'plugin', 'target_url', 'stream']
66 endpoints = ['log/apps']
70 .. :quickref: CaaS - Log forwarding;Add the log forwarding configuration entry
72 **Add the new containerized application log forwarding entry to configuration**:
78 POST /caas/v1/log/apps HTTP/1.1
79 Host: haproxyvip:61200
80 Content-Type: application/json
81 Accept: application/json
85 "plugin": "elasticsearch",
86 "target_url": "http://elasticsearch.elk.svc.nokia.net:9200",
90 :<json string namespace: Apply forwarding for containers deployed in this namespace
91 :<json string plugin: Plugin that handles log forwarding, one of ``elasticsearch``, ``remote_syslog``
92 :<json string target_url: Log storage service URL (eg. ``protocol://ip-or-fqdn:port``)
93 :<json string stream: Output stream source of gathered logs, one of ``stdout``, ``stderr``, ``both``
100 Content-Type: application/json
108 :>json int code: The status code, 0 when OK other when error
109 :>json string description: The error description, present if code is non zero
110 :>json string data: Empty string in all cases
111 :statuscode 200: no error
112 :statuscode 401: on authentication error
115 def func(self, caas, args):
116 entries = caas[self.KEY_NAME]
118 if args['plugin'] not in SUPPORTED_BACKENDS:
119 raise ValueError(PATTERN_SHOULD_BE_ONE_OF.format('plugin', ', '.join(SUPPORTED_BACKENDS)))
120 if args['stream'] not in SUPPORTED_STREAMS:
121 raise ValueError(PATTERN_SHOULD_BE_ONE_OF.format('stream', ', '.join(SUPPORTED_STREAMS)))
122 if entries.count(args):
123 raise ValueError('Already exists')
126 return self._modify_caas_config(func)
130 .. :quickref: CaaS - Log forwarding;Get the existing log forwarding configuration
132 **Get the existing containerized application log forwarding configuration**:
134 Optionally request could filter entries by namespace.
140 GET /caas/v1/apps HTTP/1.1
141 Host: haproxyvip:61200
142 Content-Type: application/json
143 Accept: application/json
149 :<json string namespace: (optional) The IP address of the server where logs are forwarded to
151 **Example response**:
156 Content-Type: application/json
167 "plugin": "remote_syslog",
168 "target_url": "tcp://http://rsyslog.log.svc.nokia.net:1234",
174 :>json int code: The status code, 0 when OK other when error
175 :>json string description: The error description, present if code is non zero
176 :>json string data: Contains the log forwarding configuration
177 :>json string id: The identifier of the log forwarding entry
178 :>json string namespace: Apply forwarding for containers deployed in this namespace
179 :>json string plugin: Plugin that handles log forwarding, one of ``elasticsearch``, ``remote_syslog``
180 :>json string target_url: Log storage service URL (eg. ``protocol://ip-or-fqdn:port``)
181 :>json string stream: Output stream source of gathered logs, one of ``stdout``, ``stderr``, ``both``
182 :statuscode 200: no error
183 :statuscode 401: on authentication error
187 caas = self._get_caas_config()
188 value = caas[self.KEY_NAME]
189 args = self.get_args()
191 for idx, v in enumerate(value, start=1):
194 if args[ID] is not None:
195 return self._result({args[ID]: value[int(args[ID]) - 1]})
196 elif args[NAMESPACE] is not None:
197 return self._result({k: v for (k, v) in data.items() if v[NAMESPACE] == args[NAMESPACE]})
199 return self._result(data)
201 except Exception as exc:
202 return self._error(exc)
206 .. :quickref: CaaS - Log forwarding;Change the existing log forwarding entry configuration
208 **Change the existing containerized application log forwarding entry configuration**:
214 PUT /caas/v1/apps HTTP/1.1
215 Host: haproxyvip:61200
216 Content-Type: application/json
217 Accept: application/json
224 :<json string id: (mandatory) The index of the entry to be modified
225 :<json string namespace: (optional) Apply forwarding for containers deployed in this namespace
226 :<json string plugin: (optional) Plugin that handles log forwarding, one of ``elasticsearch``, ``remote_syslog``
227 :<json string target_url: (optional) Log storage service URL (eg. ``protocol://ip-or-fqdn:port``)
228 :<json string stream: (optional) Output stream source of gathered logs, one of ``stdout``, ``stderr``, ``both``
230 **Example response**:
235 Content-Type: application/json
243 :>json int code: The status code, 0 when OK other when error
244 :>json string description: The error description, present if code is non zero
245 :>json string data: Empty string in all cases
246 :statuscode 200: no error
247 :statuscode 401: on authentication error
250 def func(self, caas, args):
252 raise ValueError(MISSING_LOG_STORE_ENTRY_INDEX)
254 idx = int(args[ID]) - 1
255 for k, v in args.items():
256 if not k == ID and v is not None:
257 caas[self.KEY_NAME][idx][k] = v
259 return self._modify_caas_config(func)
263 .. :quickref: CaaS - Log forwarding;Delete the entry from log forwarding configuration
265 **Delete the entry from containerized application log forwarding configuration**:
271 DELETE /caas/v1/apps HTTP/1.1
272 Host: haproxyvip:61200
273 Content-Type: application/json
274 Accept: application/json
280 :<json string id: (mandatory) The index of the entry to be deleted
282 **Example response**:
287 Content-Type: application/json
295 :>json int code: The status code, 0 when OK other when error
296 :>json string description: The error description, present if code is non zero
297 :>json string data: Empty string in all cases
298 :statuscode 200: no error
299 :statuscode 401: on authentication error
302 def func(self, caas, args):
304 raise ValueError(MISSING_LOG_STORE_ENTRY_INDEX)
306 caas[self.KEY_NAME].pop(int(args[ID]) - 1)
308 return self._modify_caas_config(func)